What is a User Oriented Architecture ?
Guillaume Saint Etienne
?? DDD practitioner / Agile Technical Coach / Tech Lead / Software Crafter / CTO ? CEO ??
While I was preparing to explain my thoughts and convictions about how to start a fresh clean architecture to my colleagues at ITER, taking in account the whole and impressive legacy base code, I was desperately feeling that, whatever you code, whatever you architect, you should place in top position only one thing: the user needs and its point of view.
By that, I mean: why shouldn't we start to think with/about the user perspective. The user, not the technician, not the architect, not the coder. Even when we have to write something quite technical, such as a Web API or a gateway/interface to something. Because, in reality, there always are “users” at some point in the flow.
For engineers like us, it's so easy to dive into the solution space without taking significant time to ask: what is the problem space?
What are the concerns we're willing to solve with our code? They usually come (the problems) from different horizons, and we have to take everything into account (hence the Essential complexity rising).
It could be from the Ops that want to put effective continuous integration; it could be another dev team that waits for a clean RESTfull API, stable and well-designed. It could (and mainly) come from all those marvelous and user-friendly UI/Web components, whatever the front stack is, because WE DON'T CARE of the technical plumbing !!! (at that point). All that points that add tangible value to the product to be delivered.
Stop thinking in terms of technology and ask yourself this simple question:
What really matters, for example, in the API I have to build ?
Will it be convenient? Will it be close to the real user actions? Will it be simple for the UI components to connect to that API? Most important: does this API have to be domain centered?
The answer is YES!
Being User Centric is to be Domain centered !
The user works in a Business Domain. Hence, Business Domains must fulfill user requirements and not developer needs! Neither a framework needs (SpringBoot or Jooby or ASP.Net MVC or whatever annoying technology you want to sell to me). Stop being fooled by those “low code” promises. Or go back to FileMaker and FoxPro then!
What really matters in your design is to start (in your mind) with the User Point of View, right while designing your REST (Web) API, Service, User Scenarios.
Even in DDD, most people start with the Core, modeling Aggregates and Entities like dead flesh. I think, if we follow DDD principles, and for example experimenting a Event Storming, or Event Modeling session, what is emerging firs is : Scenarios. User stories if you want to name them like this. Entities are here, but blurry, incomplete drafts.
Don’t focus on Models, let them emerge
The engineers want everything to be complete, perfect, entirely modeled as perfection. They go wrong.
We need to work with incertitude in minds. We walk through quick sands. That's how it goes.
So why on earth, we desire a perfect modelization artifact to be ready before writing those stories? The guys from Merise, that's what they imagined: writing perfect models, beautiful MCD and MRD, all relations set. Like a whole spherical perfect world map where everything is already discovered and clear and stable? Then writing the implementation should be only 10% of the remaining time of the project ? Even worst: some (still) thought that from UML diagrams, the code could be completely auto generated. I put my bet that even AIs will not manage to achieve this.
And guess what? It is no use. It is just a waste of time.
The genius syndrome and over engineering
Software Architects often see themselves has inventors. Or worse: geniuses !
Some trend to think that technology can solve everything. That the solution is more important than the problem.
The Service Layer Problem
If you think in terms of Service, Business Service, but you don't serve your customer's concerns, the chance of going wrong that way are high.
A lot of developers thinks of Business Services in terms of a technical layer, that will connect various technical and complicated connectors, to database, to external services, to third party libraries, to high grade algorithm, to security concerns... but never what the user wants.
The CRUD and Database problem
Those kinds of bad habits come, and will always come, from CRUD...?that is for me the root of all problems; a formula that fits to any premature optimization. Indeed, CRUD is somehow a premature optimization.
Since MERISE put the worm in developer's brains, I'm sure that 80% of them think that implementing CRUD operations is 80% of the effort they have to do, in order to produce a software solution that fullfill any expectations.
Thinking that data is more important than behaviors and user scenarios, they immediatly start to design how data could look like in a database. And then, nothing can stop them: they will already choose Mongo, Firebase or the SQL engine of the world as the heart of the application. And of course, they put all dependencies on it. Even more easily if they use those damned ORMs that fool them so quickly (look, I can turn my tables into objects, I'm the champion of CRUDy OOP!!!)
Therefore, writing fast code that follows CRUD principles, and thinking they so smart, they tend to generalize, make it more abstract, more generic. All those beautiful object patterns. And create premature "optimization" that will quickly turn into a nightmare when it comes to deal with the "20%" (*) non-CRUD operations, that are the heart of the business, and the genuine source of the value for the users.
(*) measured into delivered value, those 20% are in fact more than 70%.
Why is delivering value not so simple?
Well... ask the users.
Do they want a CRUD only application? No. They want interesting things to happen. They want rules, they want interactions, they want consequences, computations.
Some complex needs, by nature.
The Complexity Challenge
They are different ways to deal with complexity. Broadly, you're falling in 2 kinds of solutions:
Two very contradictory approaches.
I saw so many projects reaching the first option without eventually evaluate the 2nd possibility. They end with writing 80% of the code quick and dirty, and realize that the 20% of the "details" they omitted in fact require … another 80% of work (hence having a 160% effort to make).
领英推荐
Complexity is hard. Simplicity is harder.
Complexity is a relative term. What’s complex for one person is simple for another. However, complexity is the problem that domain-driven design was designed to solve. In this context, complexity means interconnectedness, too many implicits, many data sources, different business goals, etc.
Domain-driven design bases on separated, clear business domains.
Divide domains into Core, Generic, Strategic is not only strategic but crucial. And it takes time, as modern business environments are very complex and wrong moves can lead to fatal outcomes. This tends to prove, once again, that a "one-size-fits-all" solution cannot definitely work. Domain-driven design can solve complex domain models, if they are connected to core business concepts, hence the (end)users concerns.
Start with practical situation: What do your users needs?
First question to ask is: who are our users??
Well, when building software, we have to think both to the real end users, the ones behind the screen and the keyboard.
But we build using tools, especially to go faster and to avoid complexity (or we tend to). I assume you already have your toys, sorry, your tools... but it's kinda the same, uh?
And so, if the users needs, come through a Graphical User Interface, then we have to be very practical for that UI, and offer "services" that ease the development for our fellow UI enthusiasts.
Go quickly in production, staying View oriented
Imagine we have an Angular based front web interface, that comes with components. If we want to have a nice demo effect, and more than a demo, an MVP, let's build with that in mind.
But of course we don't want our solution to be tight coupled to any particular JS or whatever UI framework. To achieve that, you will keep in mind the good practices of Clean and Hexagonal architecture: https://thekitchen.gitlab.io/en/post/frontend-hexagonal-architecture/
Whatever the UI technique you choose, a good practice is to build a Port to let that FrontEnd app communicate with the domain. Keep in mind that in Clean Architecture, the domain never has a clue of what is happening in Ports and Adapters (DB remains in Adapters, invisible to others).
Think your Web Adapter/API to be concordant with the UI framework
?In clean architecture, a driver adapter is responsible for interacting with external frameworks and tools, such as web frameworks, databases, or third-party services.
The purpose of the adapter is to convert data and operations from the application's inner layers to a format that the external framework understands and vice versa.
While Angular and React are both popular JavaScript frameworks for building web applications, they have different approaches, syntax, and component lifecycles.
Creating separate adapters for each framework allows you to tailor the integration to the specific requirements and conventions of each framework.
Write for daily user tasks, scenario oriented.
If there is no logic yet, why writing entities, aggregates and so on? Just for the sake of it?
If often saw people starting doing a BUFD (Big Upfront Design) even in DDD, while trying to model first all the aggregates and entities. With hindsight, I now think it is often too soon and a reflect of premature optimization, one more time.
That leads to? aggregates (and entities) being just (another) data model.? Therefore, quite anemic. It's all wrong. Domain Model != Data Model What we absolutely want to avoid is an anemic domain model .
Event Storming is telling Stories
It’s a very good way to start thinking at the space of the problem. Let the user needs pop out from the collective brainstorming. That's what Event Storming workshops are made for. And when Entities comes, well start thinking of Views instead of Aggregates. So they will arrive a bit later.
Meanwhile, why don't we start with a (almost) Read Only version of Entities, for the need of an MVP?
Seeing is believing.
Yes, let's discover the model by just “seeing” it. Seeing as it needs to be seen (read) by the UI, the front end. Great start. Conversation will arise, don’t worry.
Domain Story Telling is another tool I like to use.
Whenever it comes from, I think the User Scenario, or User Journey, or a short lane in the Event Storming is a good way to start developing the solution.?
Place your scenarios under tests
We should start coding with tests, test about the outcomes of those scenarios. Just to verify that they are coherent, that they really tell the truth. Not start to model entities and their invariant at the very first time, but let them appear as a need to fulfil the scenario, not a sacred Graal in itself.
?Entities are placed in the core. The core is heart. But the Drivers elements (in the hexagonal/clean architecture) are the reason for the Core to exist. And the Driven components, well, they are just to be treated as “slaves”; as they shall have no influence at all.
The Core Domain shall not exist without user inputs, user expectations, user rules. So, don’t rush into “guessing” what's in the core without scenarios first. And stop putting everything into a perfect model with all relations and premature stuff.
Otherwise, the artifacts will be too theoretical, reflecting too much the feeling of an engineer who like engineering everything.
Let’s always start from practical use cases. Not dogmas.
The richer Domain Model comes first from a rich User Experience.
Thank you for reading.