Monday, April 12, 2021

The best time to do technical pre-design

I've been seeing developers discussing the details of implementation a lot recently. They spend a lot of time writing documents for choosing an option of data models, drawing flow diagrams to explain different ideas for a requirement, discussing how to entities design should be in tech huddles. But they just don't write code.


Pre-designs are required but not all the time. Sometimes the best way to find the best design is to write code. In this blog, I'm going to explain when we should do pre-designs and when should not.

What is design (noun)?

  • High-level design: the structure of domains, the interactions (also called contracts or interfaces) between different high-level domains

  • Middle-level design: the structure in the high-level domains, which is about subdomains and systems, plus the interactions among them

  • Low-level design: the structure of code in a system, which is about components (packages, classes), plus interactions among them.

Interactions include:

  • what - input and output

  • how - invoke or subscribe, plus the direction of the dependency

 


What is good design?

A good design supports future changes at a low cost at all levels.

What is a design activity?

Try our best to make a series of decisions for good designs at different levels.

 

Can we get the best design from the first design activity?

Of course, NO. Decisions in design activities are objective. They are very similar to bets. We are not able to verify the correction until we implement them.

The only way to find the best design is through evolutions by following the 4 rules of simple design and YAGNI all the time. This is very similar to the TDD practice.

However, the cost of each evolution is also based on the level of designs. Code-level refactoring is much cheaper than the system level. The reason is the complexity of high-level designs is much higher than low-level designs.

Diagram 1: cost to make an evolution (design change) vs the complexity of the current design

 

The diagram shows that it is not possible to only rely on evolutions to find the best design when the system gets complicated. So we have to find another way to maintain them at a reasonable cost. Since we can’t reduce the cost of each change, the only way is to reduce the number of changes. This is why we need the pre-design activities which should help us to avoid some future changes. But please notice that we’ll no longer be able to have the best design, and we have to rely on experts to make good decisions.


Summarize the 2 ways to make a good design:

  1. TDD - refactor to make the design better

  2. Pre-design - rely on experts to make good decisions

 

When is the best time to have pre-design activities?

Diagram 2: compare 2 ways to make a good design

 

The diagram shows that if the systems involved (eg. systems in different domains) have high complexity, pre-design may perform better than the TDD approach. But keep in mind that keeping the designs in high-level (like contracts between domains) and avoiding the internal designs in each system because TDD is still the best approach for the internal designs which don’t have the high complexity.

 

Summary

We should follow the TDD approach by doing a lot of refactorings to find the best design in low-level designs. We should do pre-design to get a good enough design in high-level designs. We can mix the 2 approaches in middle-level designs.

 

By the way, a small company such as a startup usually doesn’t have high-level designs. So they can iterate very fast without having pre-design activities. However, they must make sure to do refactorings to keep the systems clean so that they can maintain the speed of delivery.

References:

No comments:

Post a Comment