From time to time everybody feels that the architecture of the software one develop is quite closer to a big bull of mud that the screaming architecture.
I give you plan of a workshop you may lead with your team. This is a part of my ArchitecturalKata for an Agile Team workshop.
What is the Goal
We want to achieve agreed and clear vision of the architecture. I am really pragmatic person. So I am not going to push you to introduce some sexy solutions as: DDD, Clean Architecture, CQRS, Event Sourcing and stuff. It may happen it may not.There are many criteria to meet to achieve these architectures. Here, our goal is to move your architecture into a better place, even it mean a step forward. We want the architecture to be more testable, maintainable and more decoupled. That's all.
What We Need?
- a team who work on the system (recommend no more than 10 people)
- 1-2 days
- silent classroom
- space on the walls or on the floor
- quite big table or space on the floor
- couple blocks of sticky notes in many colors
- colored markers
- pair of scissor
- printer paper
- big flip-chart sheets
- paper tape
- a computer with a code baseline
- beamer (useful but not necessary)
See Responsibilities
Because flow of that workshop varies in some details depends on the software size and granulation, I give you an example for the quite big legacy system (developed from more than a decade, where primary building blocks are components containing many classes).- First, capture all your components. Write each on a sticky note. It may be hundred of them or more but not so much :)
- Then look into the source code and try to name responsibilities. Responsibility is a role of the component and the way how it serve to others. So, you will find them looking at the public methods, events published, signals sent. Sometimes one strange method is one responsibility, other time group of related method define a responsibility.
- That's important: name only those responsiblities you see in the code, not those you think they are
- Don't be too detailed with the granulation of the responsibilities. Be ready to regroup and rename them any time you want
- Probably you know that in a legacy code components have many responsibilities, so name them explicitly and write them on small stickies. Next put small stickies on components they come from
- You will see than you have two to four components which looks like stars with its satellites :) These are components where single responsibility principle was really abused. There is much code inside
Redefine Responsibilities
Now its time to redefine responsibilities of the components. Organize your components obeying following rules:- A component has exactly one coherent responsibility
- You are allowed to add new components
- You are allowed to remove components
- You are allowed to rename components
- Add/Remove/Rename components and reorganize responsibilities stickies
- Repeat until every single component have sort of small stickies and all of them describe one coherent responsibility
Redefine Communication Between Components
- Now draw directed lines representing communication between components and note purposes of a communication just right above the lines. A line starts from a component which initiate communication.
- There is one rule during this exercise: a line cannot cross an other line. I will explain why at moment.
- Sometimes you will discover a cyclic dependency between components, so remove it, if needed.
Cluster Components
- The rule "don't cross the line" caused that components which work closely are stuck closely.
- Try to circle clusters of closely related components. But there is important rule: look for the clusters related to the functionality of the system. You may ask yourself: What is the core cluster where we have minimal deliverable functionality? How to cluster components to extract potentially optional functionalities?
- Name these clusters
Define Clusters API
Now we want to see high-level view. We want to extract fine grained and decoupled clusters enclosed in modules, processes or separate applications.- First define an API for the clusters.Finally we want cluster-to-cluster communication instead of component-to-component. A component-to-component communication is fine inside the cluster, but not between them.
- API receives communication from other clusters and distributes it inside of the cluster. It also translates the inside-cluster communication into outside one.Technically that translation layer will be some combination of facades and adapters.
- Defining API remember that we have: exposed interfaces and required interfaces. Define both.
- Also explain how the inside-cluster components talk to each other.
- This is important: obey the encapsulation rules: nothing from inside of the cluster is seen to the outside world
Define Communication Between Clusters
- Draw communication between clusters. It will be API-to-API communication, it mean exposed interface to required interface.