In today’s article we are going to establish the science and process of UI Architecture.
Many people refer to software engineering as a craft. Whilst the metaphor has merit, I think that it leaves too much to the imagination. A craft denotes a fluid approach to building something using ‘artistic’ approaches.
In my experience; building software should not be treated like art, when it’s treated as such you end up with lots of egotistical developers all applying what they think is ‘pretty’ to an ever-expanding hodgepodge of bloated, repeated and tightly coupled code.
There is a direct correlation to how well a software team functions and how congruent and cohesive their code base is. Good code = good team. So, if we want coherent software and coherent teams then we do not want individual art. We want structural science.
There are two high level things we must understand if we want a way to build UI architecture scientifically.
The most applicable outcome we can decide for any software project is that we not only have a specification of our system, but also have proof our system works. The quickest way to do both of these is to write automated tests. We should position UI architecture around the first priority when wiring our apps; testing!
Our week to week, day to day and minute to minute development cycle carries uncertainty. To decrease uncertainty, we implement rules that enable us to de-risk a lot of the process. What are these rules? These are the rules of ’architecture’ when building UI apps.
The rules of UI architecture are like guiding principles that help us with uncertainty, how? Because the only practical way to remove uncertainty is to improve certainty, through slowly but surely building our code around our tests, which check our specification as we already saw; each test becomes a little step forward on our journey to completing our app.
But there is a hidden benefit to taking each step with a test. It forces us to keep our code ‘testable’. Testable code is better than normal code because it’s decoupled. It has to be if we want to be able to run simple scenario testing without the overhead of end to end testing.
So… writing tests is actually the best way to force good architecture scientifically in our UI app, because it lets us slowly move forward through our problem domain and iterate on code until we KNOW it’s right, whilst forcing us to keep our code testable.
The first rule you should apply if you want to create testable code, is to separate out the UI portion of your app that houses all of your UI framework code (Components, Hooks, Directives etc) and keep these all well isolated away from what you could call the ‘domain’ of your app.
Specifically this means you can isolate your presentation and business logic separately (POJO in the diagram), then when you need to write tests you don’t need to test the complex HTML, you just test the code which powers the data models and business logic. In my experience when covering just this section, as long as your UI code is simple enough (which will be helped by separating things like this) you may find you do not need to test the UI/Markup.
In our UI Architecture Academy we have an entire section on ‘bad markup’. It shows you how to transition from deeply nested and complex view markup into simple and flat trivial markup, which actually need very little testing since it’s just a semantic/declarative language.
The second rule is to connect up your architecture using the Reactive programming paradigm. In a nutshell what this means is centralising some sort of state in your app and then allowing all the other layers in your app to get updates when it changes, we call this central bit the ‘core’.
We also recommend Reactive streams to change the shape of your data in the app and be very clear at each layer what is going on. We try and teach students to visualise the ‘heart’ of their app with everything simply subscribing to cascading changes. This way you get a one-way predictable data flow. The one-way data flow is the second rule which will help you write testing because now your tests have a clear policy for how synchronicity is handled. This means you can write more complex tests which test larger parts of the overall system.
If we want to create better software then we need a predictable and process driven approach which lets us progressively add code whilst maintaining a good architecture.
In light of there being a varying understanding of what ’good’ architecture is in general; we can define it simply in terms of what it enables; this being the ‘scientific’ approach. Loosely defined; a scientific approach enables a practitioner to freely test ideas against a specific hypothesis in order to derive a desired outcome. In our case the desired outcome is testable code (with tests).
With regards to building a UI architecture that matches this goal we can broadly declare two global rules which enable the scientific approach to happen;
1) Our UI architecture lets us isolate our business and presentation logic from the UI framework
2) Our UI architecture should be based on the foundation of a reactive one-way data flow
By allowing the predictable isolation of the core they can write cohesive but decoupled tests which simply drive out complex use cases without the overhead of ‘the web’. At Logic Room we call this approach ‘fast testing’.
So, we will now be in a position to build gradually with certainty, testing each idea out, iterating on failure and eventually finding the correct and accurate path through the problem domain until we are left with the right answer. This iterative, step by step model which moves us to certainty with predictability, whilst not getting dragged into the technology or our UI app (frameworks, web etc etc), is the most ‘scientific’ way we can architect our UI apps!
Download our 28-page book exploring big picture ideas to help you create better architecture with any UI framework (inc. React, Angular or Vue).