Architecture 101: Thinking about Design

Architecture is about many things but I always believed *Design* was in the heart of architecture. However how we design something? There are many aspects to cover. In order to do better designs you need basically 3 things:
* Problems to exercises your design skills.
* A continuous learning process: Knows your tools, technology and always look for new approaches and techniques.
* Review and Feedback process which could be done via a series of practices like Design Sessions, Design Review, working POCs. 
It's also imperative to know your tools, what features do you have in your disposal, what techniques people often use, what principles can be applied and are often good ideas like Isolation, Testability, Debugability and which ones are smells or often anti-patterns like using Cassandra as a queue or Reflection in Java without caching. There are always macro and micro concerns you need to take into account. At the end of the day, small things can make a big difference in designs like database i.g Postgres XID size(tradeoffs between performance and safety).IMHO it does not matter if you are designing a database or a shared library or a simple service for your org the principles are the same(although the tradeoffs and knowledge and problem space are completely different).

The Solution Map

I have drawn a simple solution map that might help you out to navigate on the problem space and arrive with the right solution. There are 4 main concepts that lead to the solution: Use Cases, Reliability, Trade-offs, and Debt constraints.


Use Case Goals: This is where you should start. Consider forces making influence here like Business Decisions(which is the lean word for Product/Software Requirements), Corner Cases: Even if someone ask you something straight like get me a glass of water will be corner cases like, if there is no water, if there are no glasses if the glass is half empty, etc... Finally, thereDesign is an important force which is the user, consumer, or developer experience. You might realize I separate that force from "what the business wants" because we should assume we dont know what the users want.

Reliability: This ideas are kind of new. However, we need to add this concepts on our solutions. One big influence here is Observability(Metrics, Traces, Logs, and Dashboards) so we need to understand whats going on. Easily we can account for other factors here like Stability. Last but not least Automation is super important, any decent solution needs to have automation. Automation does not mean only automated deploys or tests but also migrations and remediations.

Trade-Offs: Solutions need to pick carefully what trade-off they dont have a choice(Nature) or the once that are choosable and like anything in life you gain one thing and you lose another. for instance we can make a system much more simple with several security mechanisms but also we will be affecting performance and user experience. Trade-offs manifest from the micro and the macro i.g Data Types(Micro) vs which Database to use (Cassandra or Postgres) macro.

Debt Constraints: Unless you are in a startup, well even if you are in a strat you will rely on existing oss software so you will be affected by debt one way or another. Working at the Enterprise field means dealing with Debt and I know this is a very bad word i.e Liability is much better. So you need to consider that will be things you don't know and will be limited. For instance, every single service in AWS has limits(i.g S3), Soft and hard ones.  It's important to consider the Debt space in a new solution to make sure you don't add more debt and you like a good boy scout let the place better them you found it.

The Main Architecture

Once you consider the factors I mention on the solution map, then you can think about the big picture(I also call it the main architecture), which IMHO has some concepts like.


The Main Architecture drawing is the big picture drawing of your solution and should contain the key elements of the solution in a very 360 high overall view. I found that's a good place to start and then you get down in levels of details.

The Big Picture means you capture the most essential and important elements of your solution. So you will focus on your core components, it does not need to have all components or all technologies, otherwise, this picture will be impossible or very hard to reason about it.

The core components need to be capture with clear and simple names. Avoid huge names and create long term abstractions which often make the design confuse and if you need to do mental mappings all the time it means your solution requires a higher cognitive load which is not good at the end of the day.

You also might want to capture the main flow. It does not need to have all sub-flows and all corner cases, again imagine you explain what A Tesla car is to a 6-year-old kid, so maybe the ballet dancing easter egg is not where you want to start.

Remember to focus on the main abstractions, so it means you do not get all abstractions but only the most important and high-level ones. Good abstractions allow us to speed up things, both on the engineering side but also on the understanding side. Complex or non-needed abstraction makes the design more complex and hard to reason about it.

The Following Components - UML is fine

Now we can go down to sub-modules, other microservices, or key components of the solution.

UML diagrams can be a useful tool because I you imagine how it should work or right a coding POC will help a lot to validate our design. UML is not evil. IMHO the notation does not matter also long as you have boxes and arrows, that all you need :-) You should see UML as a thinking tool, not as a documentation tool.


IMHO Class and Package diagrams are pretty useful, should I do it for all classes of the system? Hell no! Sequence and State Diagrams can be very useful too but they need to be picked very carefully. They are not tools for the everyday job. The sequence diagram is useful if you have a protocol or lots of calls in a complex flow. State Diagrams are good for FSM or in cases where you have lots of state transitions or complex flow control. Often people do not think about Database modeling. If you work with NoSQL that not an option, how you model data makes all the difference. Another important aspect of solutions design is to consider.

While you are doing design it's easy to think too much ahead since the "paper" or drawing tool often accept anything and does not have a limit. It's important to think big but execute small, and break your ideas in versions like solution version 1, solution version 2, and solution version 3. In this way, you will execute in a more agile way but also will avoid too much complexity on day one.  Design is an organic/live process that takes time to get maturity on it and review and feedback are mandatory tools to improve. It's hard to improve if you do not learn new ideas and techniques so make sure you look how other stuff gets built.

Cheers,
Diego Pacheco

Popular posts from this blog

Kafka Streams with Java 15

Rust and Java Interoperability

HMAC in Java