Use Git and Markdown to Store Your Team’s Documentation and Decisions

Do you sometimes feel like Bill Murray in Groundhog Day? Reliving the same day over and over again? I sure feel like that in some discussions with my team: revisiting the same discussion multiple times, because we fail to document decisions properly. Redrawing that diagram one more time, to come to the same conclusion. Searching for that one document in your email? Sifting through several versions of the same document, not sure which version is the latest? 

Next time around you can avoid these situations, using simple tools that your team is already using: Git and Markdown. Add Architecture Decision Records into the mix to capture the important decisions and the context in which those decisions were made.

Documentation should be an artifact of your software development process

Documentation can only add value if everybody knows where to find it and can edit it easily. For development teams that means keeping the documentation as close as possible to the source code. Putting both in the same version control repository instantly makes sure everybody knows where it is and how to edit it. The most often used solution for version control is Git. The Stack Overflow Survey of 2018 reported that 87.2% of the developers consider Git their favorite version control system. It is a powerful, distributed version control system, developed with speed in mind. Perfect to keep track of changes in your documentation, as Git keeps a record of who changed what and why.

Storing both code and documentation together allows the team to treat the code as documentation and supplement where necessary with documentation as code. Meaning all code should be self-explanatory as much as possible, but when additional documentation is necessary, you treat your documentation as an artifact of your software development process. Just like the code, documentation is under version control, written in plain text and subjected to code reviews.

You already have all the tools you need

The most often used tool to write documentation in plain text is Markdown. All major software development tooling, such as Gitlab, Azure DevOps & GitHub, support Markdown files nowadays. Markdown is a lightweight markup format, that converts easily into web pages. You might have seen it as a file in one of your repositories. However, it can also be used to document other aspects of your application. Because the files are stored in Git as plain text, it is easy to include documentation changes in your merge requests. The web interface of your Git repository will automatically convert the Markdown format to a nicely formatted page for everyone to read. Nothing is keeping you from starting right now, the tooling is already present, all it takes is one text file!

Getting it right

Finding the right level of documentation for your team can be quite a struggle. The Agile Manifesto calls for working software over comprehensive documentation, which is often wrongly interpreted as not having any documentation at all. There’s a lot of wiggle room between “no-documentation-at-all” and “everything-documented-to-a-tee”. Lightweight, easy to maintain documentation is the sweet spot you should aim for. Avoid going too heavy on the details, as keeping everything up to date will become a burden as your documentation grows. Include too little details and your documentation will not add value.

Architecture Decision Records (ADR) is a technique to help your team document decisions made. It is originally intended to record architecture related decisions, but I’ve had good results documenting a wider range of decision types. ADR provides a template to motivate to your future self why certain decisions have been made. In a Markdown, you clarify which options have been considered and why the chosen option appeared to be the best at that point in time. You include the goal you were trying to achieve and any negative side effects you consciously accept by choosing this option. 

“In the context of <use case/user story u>, facing <concern c> we decided for <option o> to achieve <quality q>, accepting <downside d>.”

Consistently expand the collection of decision records in your project and this collection grows to become a valuable source of information for the developers that may join your project after you. They can use it as a sensemaking tool for the code base, to figure out why things evolved as they did. We’ve all been in situations where the inherited code made no sense; Architecture Decision Records can help you navigate those kinds of situations with more confidence.


  • Install a Markdown extension for Visual Studio Code to get a live preview right in your editor.
  • Make sure to add or adjust documentation for each user story. Add a check to your team’s Definition of Done as a reminder if necessary. 
  • Consider using Behavior Driven Development, to reduce the manual effort involved with updating documentation and use your acceptance tests as living documentation.
  • Start with recording your decisions and don’t get hung up on the tooling around ADR. Starting is far more important because, in the end, it’s just a bunch of text files!
  • Non-technical people may struggle with Git, pair with them to teach them how to use Git. Alternatively, you can show them how to create branches through the UI and edit the documentation there. As a result, everybody can contribute and the documentation can still be reviewed. All Git repositories with a web UI support this workflow.
  • Looking to migrate existing documentation to Markdown? Have a look at the Pandoc project, it can convert between many different file formats, including Word.

Migrating App Engine to Go 1.11 – the price of vendor lock-in

If you are using App Engine on the Google Cloud Platform (GCP) you shouldn’t be too surprised when receiving an email stating the current version you are using is being deprecated. Chances are you haven’t read Google’s deprecation policy, which also applies to App Engine (listed here). which basically states that if Google decides to upgrade their services and deprecate older version, they can. And will. And you will be forced to follow along.

So of course, the email which came on June 27, 2019 should not have come as a surprise to you:

Hello Google App Engine Customer,

We’re writing to let you know that Go versions prior to 1.11 are no longer supported on App Engine, and new deployments using these language versions (1.6, 1.8, and 1.9) will not be available starting October 1, 2019.

This left about 3 months to upgrade.

Read more →

Where to begin when joining your first Scala Spark project

Man, Apache Spark is some powerful stuff! Add a fancy and fun language called Scala and you feel like you can do a whole lot of cool things with a lot of flexibility! This is my current standpoint on the subject, after a short year of working with this setup. The first month was a completely different story. Let me share some tips that really helped me out when I started working on an existing Scala-Spark codebase.

Read more →

Five quality patterns in Agile development

In this blog series, I’ll discuss five quality patterns in Agile development to deliver the right software with great quality.

For years now companies have been adopting Agile ways of working and mostly the Scrum framework as their way to develop software. Scrum is all about working in dedicated teams on small increments of working software. Software that can potentially be released every single sprint. I’m sure you agree with me that this means that this software is therefore always tested every sprint as well. How could we otherwise release it right? This blog is about a trend I have noticed in a lot of companies that after time teams have more and more issues delivering quality software that conforms to business requirements.

Read more →

Why Integration Tests won’t save you… or your software

Did the title tease you? Great, job is done! Today I will tell you my story about Integration Tests; it came after another knowledge share lunch with my pal Kenny.

By this definition an Integration Test is

(…) the phase in software testing in which individual software modules are combined and tested as a group. Integration testing is conducted to evaluate the compliance of a system or component with specified functional requirements. It occurs after unit testing and before validation testing. Integration testing takes as its input modules that have been unit tested, groups them in larger aggregates, applies tests defined in an integration test plan to those aggregates, and delivers as its output the integrated system ready forsystem testing.

Sounds pretty waterfall, right? It is! also, the implementation approaches that I observed creates huge dependencies between teams, coupling the software release process.

Read more →

Uncle Bob and my personal programming Kata

My first [Uncle Bob] event was the 2017 [GoTo conference] in Amsterdam, where Robert Martin delivered a talk like he must have done a thousand times. And many of you will probably have seen some version of it way back when. For me it was all new, having managed to somehow avoid the experience for years. He said many things that made sense to me at the time, but what got stuck in my head was the idea of a programming Kata. The advice I distilled from his words was to take a small programming problem and try to implement a solution over and over again. The actual solution would be less important than the act of solving the problem. Allowing you to experiment in a safe and well known environment. Small techniques for problem solving would gradually become part of muscle memory, much like happens, or so I’m led to believe, in martial arts.

I liked the idea and found myself a small problem: read more…

Frictionless checkouts for GAMMA and KARWEI

Over the years, Xebia has been the driver of Agile software development at Intergamma, known for the GAMMA and KARWEI DIY stores. A year ago, we set out to replace the checkout process for their webshops. The existing checkout was slow and cumbersome to use, and no longer on par with other parts of the website. We knew there was a lot of room for improvement. In order to justify the investment we needed measurable results quickly. Within a year, we’re consistently seeing a significant conversion rate improvement.

Before starting out to replace the checkout, we discussed the technology stack and general approach. We had prior experience with React and Next.js, but decided against Next.js because of the complexity it adds. A checkout app also doesn’t need to be indexed by search engines, which is why you’d otherwise want to use Next.js. We decided to stick with a standard React setup, which enables us to focus and keep things simple. In order to measure our success, we set up A/B testing to directly compare the old and new checkout running in parallel.

Read more →

Automatic database sharding with Alibaba Cloud Table Store

At some point in your application’s lifecycle, there might come a time when you need to start scaling your data storage. If you are storing media files or other blobs that have no relations between them, you can easily add storage capacity to solve the problem. For (semi-)structured data in a database however, scaling is a whole different story. Simply adding database instances is not enough. You will need to reconsider the usage patterns and decide what solution solves the problem you have. If your database is hitting resource limits because it is accessed very frequently, adding an asynchronous read replica might be the way to go. If the size of the data is the issue and lookups become very slow, you might consider sharding your database.

Read more