0% found this document useful (0 votes)
55 views

Clean Architecture V1.5

An important architecture should be clean, simple, flexible, evolvable, and agile. A clean architecture is easy to understand with consistent design decisions. An agile architecture supports changing requirements through flexibility and enabling quick changes. A good architecture allows decisions to be deferred until more knowledge is gained.

Uploaded by

the4power
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views

Clean Architecture V1.5

An important architecture should be clean, simple, flexible, evolvable, and agile. A clean architecture is easy to understand with consistent design decisions. An agile architecture supports changing requirements through flexibility and enabling quick changes. A good architecture allows decisions to be deferred until more knowledge is gained.

Uploaded by

the4power
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2

Why is a clean, simple, flexible, evolvable, and agile Simple architecture Agile architecture Defer decisions

architecture important? An architecture that is easy to understand. Simplicity is, however, An architecture that supports agile software development by enabling the Decide only things you have enough knowledge about. Otherwise find a way
Software architecture is the high level structure of a software system, the subjective. principles of the Agile Manifesto [6]. to defer the decision and build up more knowledge. A good architecture
Clean simple flexible evolvable agile Architecture
allows you to defer most decisions.
discipline of creating such structures, and the documentation of these Consistent design decisions Allow change quickly
structures. [1] One problem has one solution. Similar problems are solved similarly. The architecture allows quick changes through flexibility and evolvability. knowledge
It is the set of structures needed to reason about the software system, and
comprises the software elements, the relations between them, and the Number of concepts/technologies Verifiable at any time
properties of both elements and relations. [2] Simple solutions make use of only a few different concepts and The architecture can be verified (fulfils all quality aspects) at any time (e.g.
In today’s software development world, requirements change, technologies. every Sprint).
environments change, team members change, technologies change, and so Number of interactions Rapid deployment learn decide enrich
should the architecture of our systems. The less interactions the simpler the design. The architecture supports continuous and rapid deployment so that
time
The architecture defines the parts of a system that are hard and costly to A reasonable amount of components with only efferent coupling and most stakeholders can give feedback continuously.
change. Therefore, we are in need of a clean, simple, flexible, evolvable, and of the others with preferably only afferent coupling. Split decisions
agile architecture to be able to keep up with all the changes surrounding us.
Always working
Size The system is always working (probably with limited functionality) so that it Split a decision into parts that can be decided at different points in time.
is potentially shippable any time/at end of Sprint. Use assumptions, E.g. the decision about persistence can be split into: Do we need
Clean architecture [3] Small systems/components are easier to grasp than big ones. Build large
simplifications, simulators, shortcuts, hard-coding to build a walking persistence? What data has to be persisted (amount, form, consistency)?
An architecture that allows to replace details and is easy to verify. systems out of small parts.
skeleton. How to access the data (latency, throughput)? What technology is best
Modularity suited?
Frameworks & Drivers Build your system by connecting independent modules with a clearly Workflow
defined interface (e.g. with adapters). Use a top-down approach to find the architecture.
Abstraction
Interface Adapters Use an abstraction to hide details so that you don’t have to decide about
Flexible architecture 1. Context the details, but can use a simulation/fake at first to build up more
Use Cases An architecture that supports change. What belongs to your system and what does not? Which external services knowledge.
will you use?
Direction of UI Separation of concerns Simplification
Entities 2. Break down into parts Simplify the problem so that a decision can be made and work can progress.
Dependencies Program Flow Divide your system into distinct features with as little overlap in
functionality as possible so that they can be combined freely. Split the whole into parts by applying separation of concerns and the single- Use this to break free from a blocking state, but be aware of the risks a
responsibility principle. wrong decision could have.
Software reflects user’s mental model
When the structure and interactions inside the software match the user’s 3. Communication Wilful ignorance
Web
mental model, changes in the real world can more easily be applied in Which data flows through which call, message or event from one part to Refuse to decide and wait until more knowledge about the problem and its
DB software. another? What are the properties of the channels (sync/async, reliability, …) potential solutions is built up.
External
Interfaces Abstraction 4. Repeat for each part Decision delegation
Separating ideas from specific implementations provides the flexibility to Repeat the above-mentioned three steps for each part as if it were your Build the (part of a) system in a way that doesn’t require any decision, by
Entities: Entities encapsulate enterprise-wide business rules. An entity can change the implementation. But beware of `over abstraction`. system. making some other (part of the) system responsible that can be
be an object with methods, or it can be a set of data structures and A part is a bounded context, subsystem or component. implemented later. E.g. instead of deciding how to persist data, make the
functions. Interface slimness code calling your code responsible for passing all needed data to your code.
Use cases: Use cases orchestrate the flow of data to and from the entities, Fat interfaces between components lead to strong coupling. Design the Architecture degrading forces This allows you to build your whole business logic and decide about
and direct those entities to use their enterprise-wide business rules to interfaces to be as slim as possible. But beware of `ambiguous interfaces`. Architectural drift persistence when implementing the host that runs the business logic.
achieve the goals of the use cases. Prefer composition over inheritance Introduction of design decisions into a system’s actual architecture that are
Architecture influencing forces
Interface adapters: Adapters that convert data from the format most Inheritance increases coupling between parent and child, thereby limiting not included in, encompassed by, or implied by the planned architecture.
convenient for the use cases and entities, to the format most convenient for reuse. Quality attributes
Architectural erosion The needed quality attributes (functionality, reliability, usability, efficiency,
some external agency such as a database or the Web.
Tangle-/cycle-free dependencies Introduction of design decisions into a system’s actual architecture that maintainability, portability, …) are the primary drivers for architectural
Frameworks and drivers: Glue code to connect UI, databases, devices etc. The dependency graph of the elements of the architecture has no cycles, violate its planned architecture. decisions.
to the inner circles. thus allowing locally bounded changes.
Program Flow: Starts on the outside and ends on the outside, but can go
Architecture killers Team know-how and skills
through several layers (user clicks a button, use case loads some entities Evolvable architecture Split brain The whole team understands and supports architecture and can make
from DB, entities decide something that is presented on the UI) An architecture that is easy to adapt step by step to keep up with changes. Different parts of the system claim ownership of the same data or their design decisions according to the architecture.
interpretation resulting in inconsistencies and difficult synchronisation. Easiness of implementation
Dependency management Matches current needs, not the future
The concentric circles represent different areas of software. In general, the The architecture of the current system should match the current needs Coupling in space and time How easy an envisioned architecture can be implemented is a quality
further in you go, the higher level the software becomes. The outer circles (functional and non-functional) – not some future ones. This results in E.g. shared code to remove duplication hinders independent advancements, attribute.
are mechanisms. The inner circles are policies. simpler, easier to understand solutions. Otherwise, the risk of waste is very a service that needs other services to be up and running, an `initialise` Cost of operations
Source code dependencies can only point inwards. Nothing in an inner circle high. method that has to be called prior to any other method on the class (better Most costs of a software system accrue during operations, not
use constructor injection or a factory).
can know anything at all about something in an outer circle. Use No dead-ends, architecture can be extended/adapted implementation.
dependency inversion to build up the system (classes in an outer circle The current architecture should be extendable and adaptable so that future Dead-end
implement interfaces of an inner circle or listen to events from inner Risks
needs can be addressed. When evaluating different alternatives, choose A design decision that prevents further adaptability without a major
circles). Every technology, library, and design decision has its risks.
one that is open for change. refactoring or rewrite.
Independent of frameworks Inherent opportunities
Architecture agnostic components Things the architecture would allow us to do (but without investing any
The architecture does not depend on the existence of some library of When components don’t care about which architecture they run in, the
feature-laden software. This allows you to use such frameworks as tools, additional effort because we may never need it).
architecture can be changed without having to rewrite the components.
rather than having to cram your system into their technical constraints. Technology churn
Sacrificial architecture [4] Availability of new (better) technologies, resulting in a need for architecture
Testable When the software has outlived its architecture, throw the architecture
The business rules and use cases can be tested without UI, database, Web change.
away and start over. This mindset can be used to build a first version with a
server, or any other external element. very simple architecture, then start over for the next. Trade-offs
Independent of system boundaries (UI, database, …) Designing an architecture comprises making trade-offs between conflicting
Rolling refactoring [5] goals. Trade-offs must reflect the priorities of quality attributes set by the
The UI, database, or any other external element can easily change without When a new version of a concept is introduced, then the old one is
any impact on use cases and business rules. stakeholders. Trade-offs should be documented and communicated to all
refactored out step by step. There can be at most two versions of a concept
stakeholders.
in an application (and it should be temporary).
Architectural aspects Layering & Structure Tips and tricks Bibliography
Persistence How to layer (direction of dependencies) and structure (organization of Start with concepts, not with technologies. [1] P. Clements, F. Bachmann, L. Bass, D. Garlan, J. Ivers, R. Little, P.
Form of data (document-based, relational, graph, key-value), backup, code into namespace, packages, …) to maximize understandability, Don’t think in technologies, think in concepts. Then choose technologies Merson, R. Nord and J. Stafford, Documenting Software
Clean simple flexible evolvable agile Architecture
transactions, size of data, latency, throughput, replication, availability, extensibility and maintainability. matching the concepts and adapt concepts to technological limitations. Architectures: Views and Beyond, 2nd ed., Boston: Addison-Wesley,
concurrency. Testability 2010.
Think about your envisioned architecture, but also lay a
Translation (UI and data) Test boundaries, shared composition root between tests and production – [2] Wikipedia, “Software architecture,” [Online]. Available:
so that the tests are as close to the production code as possible - with the
way from here to there.
Static (e.g. resources) vs. dynamic, switchable during Break your architecture work into steps. Use assumptions and http://en.wikipedia.org/wiki/Software_architecture. [Accessed
implementation/installation/start-up/runtime. ability to replace process external dependencies (storage, filesystem) in 2015].
tests. simplifications in early steps. Always make sure that there is a path from the
Communication between parts current architecture to the envisioned architecture. [3] R. C. Martin, “The Clean Architecture,” [Online]. Available:
Asynchronous/synchronous, un-/reliable, latency, throughput, availability of Priorities Most of the time, persistence is a secondary thought http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-
connection, method calls/events/messages. Simplicity before generality [7] You always have some data. But that is no reason to start your design with architecture.html. [Accessed 2015].
Scaling Concrete implementations are easier to understand than generalised the database. Business logic and workflows are more important. [4] M. Fowler, “Sacrificial Architecture,” [Online]. Available:
Run on multiple threads/processes/machines, availability, consistency, concepts.
Decouple from environment http://martinfowler.com/bliki/SacrificialArchitecture.html.
redundancy, monitoring, manual/auto-scaling. Hard-coded before configurable Design everything so that it has to know nothing about its environment.
[5] [Online]. Available:
Security Configurability leads to if/else constructs or polymorphism inside the code,
resulting in more complicated code. Prototypes, proof of concepts, feasibility studies https://lostechies.com/jimmybogard/2015/01/15/combating-the-
Authentication, authorisation, threats, encryption (of communication and Break risks and grow knowledge fast, then decide. lava-layer-anti-pattern-with-rolling-refactoring/.
data). See [9] Use before reuse [7]
Don’t design for reuse before the code has never actually been used. This Use architecture patterns as inspiration, not as solutions. [6] “Manifesto for Agile Software Development,” [Online]. Available:
Journaling, auditing Architecture patterns are good examples of solutions to specific problems. http://agilemanifesto.org/principles.html. [Accessed 2015].
Operations, granularity, access to journal, tampering, regulatory. leads to overgeneralisation, inapt interfaces and increased complexity.
Use them to find solutions for your problems and do not apply them to your
Working before optimised [7] K. Henney. [Online]. Available:
Reporting problems.
http://www.artima.com/weblogs/viewpost.jsp?thread=351149.
Access to data (production/dedicated database/data warehouse), delivery First, make it work, then optimise. Premature optimisation leads to more
mechanism (synchronous/asynchronous), formats (Web, PDF, …). complex solutions or to local instead of global optimisations. Architecture smells [8] D. Leffingwell, “Principles of Agile Architecture,” [Online]. Available:
Causes: applying a design solution in an inappropriate context, mixing
Data migration, data import Quality attributes before functional requirements design fragments that have undesirable emergent behaviours.
http://scalingsoftwareagilityblog.com/wp-
Use quality scenarios to guide your architectural decisions because most of content/uploads/2008/08/principles_agile_architecture.pdf.
Available time frame for migration/import, data quality, default values for
missing values, value merging/splitting. the times, quality attributes have more impact than functional Overlayered architecture [Accessed 2015].
requirements. When there are layers on layers on layers on layers ... in your application.
Releasability [9] [Online]. Available: https://www.owasp.org.
Not providing abstraction, lots of boilerplate code.
Release as one, per service or per component (e.g. plug-in). Automatic or
Combined small systems over building a single big system
Overabstraction [10] [Online]. Available: http://semver.org/.
manual release. Big systems are more complicated to comprehend than a combination of
small systems. But beware of complexity hidden in the communication Too abstract to be understandable. Concrete designs are easier to [11] [Online]. Available:
Versioning between the systems. understand. http://thinkrelevance.com/blog/2013/10/07/begin-with-the-end-in-
Product: One product vs. a product family, technical/marketing version, mind.
manually or automatically generated, releases/service packs/hot fixes, Principles [8] Overconfigurability
Everything is configurable because no decisions were made how the [12] [Online]. Available:
SemVer. [10] The teams that code the system, design the system. software should behave.
Data: versioned schema Teams themselves are empowered to define, develop, and deliver software, http://www.planetgeek.ch/2014/06/17/effective-teams-know-your-
and they are held accountable for the results. Overkill architecture code/.
Backward compatibility A simple problem with a complex (however technically interesting) solution.
APIs, data (input/output/persisted), environment (e.g. old OS). Build the simplest architecture that can possibly work. [13] J. Garcia, D. Popescu, G. Edwards and N. Medvidovic, “Toward a
Simplicity leads to comprehensibility, changeability, low defect introduction. Futuristic architecture Catalogue of Architectural Bad Smells,” [Online]. Available:
Response times The architecture wants to anticipate a lot of future possible changes. This http://softarch.usc.edu/~josh/pubs/qosa_2009.pdf. [Accessed
Service time (actually performing the work) + wait time + transmission time When in doubt, code it out. adds complexity and most likely also waste. 2015].
Get real feedback from running code, then decide.
Archiving data Technology enthusiastic architecture
Data growth rate, access to archived data, split relations in relational data. They build it, they test it. Lots of new cool technology is introduced just for the sake of it.
Testing is an integral part of building software, not an afterthought.
Data Validation Paper tiger architecture
Where and how is data validated (UI, backend). How violations are reported System architecture is a role collaboration. The architecture exists only on paper (UML diagrams) with no connection to
(synchronous, asynchronous e.g. task system). Actions taken on violations. The whole team participates in architecture decisions. the reality.
Distribution There is no monopoly on innovation. Connector envy [13]
Beware of the fallacies of distributed computing: the network is reliable, Every team member has time to innovate (spikes, hackathons, pet project). A component doing the job that should be delegated to a connector: Legend:
latency is zero, bandwidth is infinite, the network is secure, topology communication (transfer of data), coordination (transfer of control),
doesn’t change, there is one administrator, transport cost is zero, the Documentation conversion (bridge different data formats, types, protocols), and facilitation DO
network is homogeneous. Also consider clock skew. Questions to ask yourself [11] (load-balancing, monitoring, fault tolerance).
Who is the consumer? What do they need? How do you deliver the
DON’T
Public interfaces Scattered parasitic functionality [13]
Versioning, immutability and stability of contracts and schemas. documentation to them? How do you know when they are ready for it?
How do you produce it? What input do you need to produce it? A single concern is scattered across multiple components and at least one
Time & Time Zones & Calendars component addresses multiple orthogonal concerns.
Local time vs. zoned time, leap days, application vs. effective time.
Manual and automatic production
Manual: someone writes the documentation, high risk of being out-of-date, Ambiguous interfaces [13]
Monitoring & Health Checks very flexible Ambiguous interfaces are interfaces that offer only a single general entry
Data to monitor, centralized data gathering, visualization, alert thresholds, Automatic [12]: generated from code, can be regenerated anytime and is point into a component (e.g. pass an object, or general purpose events over
alert communication to team. therefore never out of date, finding right level of abstraction is hard. Works an event bus). They are not explorable.
good for state machines, bootstrapping mechanics, and structural Extraneous adjacent connector [13]
History breakdown.
Ability to reconstruct data at a certain point in time and to show changes Two connectors of different types are used to link a pair of components.
over time for debug purposes, tracing and as a feature. About now, not the future E.g. event (asynchronous) and service call (synchronous).
Only document what you did, not what you want to do. Event: loosely coupled → availability, replicability.
Exception Handling Method call: easy to understand.
Retries, rollback/compensation and rerun in case of an exception, alerting. Shared Both: neither.
The whole team participates in producing the documentation.

This work by Urs Enzler is licensed under a Creative


Commons Attribution 4.0 International License. Urs Enzler www.bbv.ch August 2019 V1.5

You might also like