← Blog

23 days ago

ADRs.

By Yossef Mendelssohn

Imagine you’re digging through some part of a system, and you come across something that looks confusing. You’re trying to figure out why something is done, or why it’s done the way it is. You have so many questions running through your head: Was this a conscious decision? Did it just happen? What are the reasons things look this way? Can things change?

Now, that last question might be the most-pressing one, and it might be possible to find the answer without answering any of the other questions. It might be possible, but that might involve some serious sciencing — experimentation, observation, &c. That could take a good investment in time and effort, and it’s a story for another time. Right now I want to focus on the other questions, and how you can make it a lot easier to answer those and also figure out the “can things change?” one as well.

What’s the solution here? As with all things, communication is key, and specifically communication of decisions. It’s not only helpful for people coming in later on, but also gets you to think through and clarify the decisions as you’re making them.

And there’s more to it than just communicating the decision. Without putting the decision in context, all you get is a list of decisions that barely adds anything significant to the “how did we get here?” confusion of looking at the current state of the system.

This is where Architecture Decision Records (ADRs) come in. ADRs provide a few things:

  • standard format for recording decisions in context
  • process for recording decisions
  • clarity on which decisions to record in this way

That clarity is a big deal. You don’t need to have a log of every decision you’ve ever made. These are ADRs, not DRs. The point is to record “architecture decisions”, significant ones that affect the architecture of the system. Michael Nygard has an excellent blog post about this, where “architecturally significant” decisions get defined as “those that affect the structure, non-functional characteristics, dependencies, interfaces, or construction techniques.” (Also, the blog post about ADRs is formatted as an ADR — delicious.)

So what does that mean? Let’s use code comments as an analogy.

It doesn’t help to do every little line and repeat the code in English:

# round the amount to two decimal places
rounded = amount.round(2)

But instead comment about why you’re doing something. The what should be (relatively) obvious from the code itself.

# this came from a calculation that could have
# resulted in sub-penny values, so round off to
# the nearest amount we can use
rounded = amount.round(2)

And even better,

# get the fees that apply to this transaction and
# apply all of them to the original amount
# some fees are percentage-based, so make sure
# to round to the nearest penny at the end
fee_amount = 0
Fee.for_transaction(transaction).each do |fee|
  fee_amount += fee.for_amount(amount)
end
rounded = (amount + fee_amount).round(2)

And that’s the important part of the ADR, the why. And even then, on the big decisions, the “architecturally significant” ones.

There are likely as many ways to handle ADRs as there are possible formats to use, but I like to keep things simple and light-weight in both the tooling and the format. To that end, I recommend Nat Pryce’s adr-tools. In addition to the easy creation of new ADRs and manipulation of existing ones, it does quite a few things I like:

  • stores the ADRs in the documentation of the project itself
  • initializes the ADR directory with ADR #1 being “using ADRs” (linking to the Nygard post)
  • uses a simple, minimal format — the base of just context, decision, consequences (with extra meta-data like the name and the status)

“Minimal format” is super important. It’s what you need without weighing down the record with a lot more cruft. If you’re working in a system where you need intensely involved checklists and questionnaires in your ADRs, you’re free to add those things as necessary (you can even provide your own template for use by adr-tools), but generally all you need to do is provide context, decision, and consequences. Sometimes these will be short and simple, and sometimes they might be more involved. Just fill out the sections as appropriate.

And I do mean you need those three, at a minimum. Let’s start in the middle, because the decision is obvious. You need to record the decision. There’s no way around that. And I’d say really be clear about the decision. Be specific.

Now, the context. This is important. This is to understand the reasoning behind the decision. This can include things like why the decision was made, or why a decision even had to be made. It could also be a fine place to point out other options, and what drove you to choose one over the others.

And finally, the consequences. Any decision has consequences, and it’s important to lay them out. While the context is why you had to make the decision, and the decision is what you decided, the consequences are what the decision gives you, and I like to separate this into pros/cons, specifically. What does it make easier or possible? What does it make harder? Is the now-harder stuff important?

This right here is where you think through and clarify the decision. Maybe one of those CON-sequences isn’t worth it. Or maybe it is for now, but might need to be revisited sooner rather than later. Which also runs into another reason ADRs are so important — this is a living system, with ongoing decisions. Some decisions are amended or superseded by later ones. Maybe the context has changed. Maybe the things that were unimportant in the past are important now, or vice versa.

Finally, let’s talk about ADRs in the real world. It’s all well and good to talk about proactively making ADRs, starting from the beginning of the project. But it’s possible that even with the best intentions you might skip the R part when making an AD. Maybe you might even have been fooled into thinking it was just a plain D and not an AD. And then there’s the more-likely scenario that you’ve found yourself in a project that hasn’t done ADRs along the way — a familiar feeling to a consultant/contractor, or even someone who’s been hired into an existing organization.

Don’t fret! As the saying goes, “the best time to plant a tree was 20 years ago; the second-best time is right now” — when the next big decision has to be made, make an ADR for it. Then make an ADR for the next one, and the next, and keep going from there. When you have (or make) time for it, record some historical ADRs. This is an art in and of itself, because without having access to people or records from the time, the decision might not be 100% clear, and the context is probably completely opaque. But all of that can be noted in a fairly sparse ADR, which can be very helpful to point out how many of these decisions were made, and promote the process of recording new decisions as they’re made, and give new decisions things to link to if they’re related to old ones.

I’m not going to promise that ADRs will keep you from ever again being in the situation of wondering about those questions I mentioned before — Was this a conscious decision? Did it just happen? What are the reasons things look this way? Can things change? — but they will make it easier, whether you use them for other people’s benefit or other people use them for yours. Or, maybe more likely, when future-you is looking back at things past-you did.

Psst! We're always looking for people, like you, who are interested in learning and motivated to get better to join our remote team. Get in touch!