A few years ago I worked for a company with a code base which had “evolved” over many years.
I never quite got to the bottom of how it had happened but the code had deteriorated over time, gradually becoming more and more complicated, and less and less consistent.
By the time I came to work on it the dev team was stuck in a vicious cycle.
The code was so verbose, and poorly structured, that even “small” changes required hours of stepping through various layers of the application to figure out how to make the change.
By the time the dev had found where to make the change, they were so worn down by the process that they’d often just make their small change and get the hell back out of there!
As the sticking plasters piled up, the app got ever harder to maintain, and lead times grew longer and longer.
Software needs structure. Without structure application code deteriorates into a tangled, unmaintainable mess over time.
But structure isn’t a silver bullet.
The challenge of structure, layers, and abstractions lies in how it separates you from the reality of the feature you’re building.
Once you’re thinking about layers, database tables, or building out services, you’re thinking in terms of abstractions.
This means you have to understand what you’re building and also how that relates to the technical abstractions you’ve created along the way.
The problem comes when the requirements change, or you realise you didn’t have all the information you needed in the first place (or you misunderstood a fundamental piece of the puzzle).
Suddenly you find yourself trying to do two things at once:
- Understand the change being requested
- Map that to the technical abstractions which exist in the code (and/or changing those abstractions if they no longer work)
Alas, the human brain doesn’t cope very well when faced with multiple, different problems like this.
If we’re talking about building a feature, UI and all, our freedom to iterate, tweak and extend the feature is hampered by the need to map it to the (often arbitrary) structure created around this feature.
What’s more, building the ‘wrong’ structure can stop you in your tracks.
In this case, technical decisions by developers who had long since left the company remained in the form of multi-layer behemoths, huge classes, full of mostly procedural code, with arbitrary and inconsistent names.
So how can we avoid this fate and build simpler web applications?
The alternative is to defer building those technical abstractions until the last responsible moment.
No-one can tell you exactly when that moment is, but it’s probably later than you think!
Apply it to your Blazor UI
When it comes to building a Blazor UI, the trick is to keep your UI code malleable, so you can evolve and iterate it without wading through layers of technical abstraction to make “small changes”.
For me this is why I tend to start with by building a rudimentary part of the UI…
It’s not just about writing some HTML and CSS, but rather a a way to better understand the feature in front of you, to really figure out what you’re working with, the feature’s purpose, and how it feels to work with in the browser.
I would try to avoid the temptation to break the UI down into separate components too soon.
It’s tempting, as parts of the markup start to become duplicated (think multiple cards in a Kanban board for example) to try and remove that duplication.
But early on in the design phase this duplication is entirely manageable, and having all the markup in one place makes it much easier to iterate, and tweak your UI.
One way to think of this is in terms of collecting enough data to inform your decisions about how to structure the code.
Data comes from building the simplest version of your feature, and spotting the patterns that emerge.
Once you have something concrete you can tread lightly and add just enough structure where it feels like i will help to keep your code maintainable, and/or separate concerns if you feel your component is doing too much.
With Blazor, this might mean you take a small piece of the UI and extract it to its own component.
Maybe you realise you have several buttons which all behave the same way, so extracting those to a separate component would simplify your UI and help maintain consistency across different pages.
But remember, for every new abstraction you add you’re adding another layer for future you (or someone else) to understand, evolve, and maintain.
In many cases, less is more.
This post was first published at https://practical-blazor-components.dev
Web development should be fun.
Write code, hit F5, view it in the browser and bask in the glory of a job well done.
But you're not basking… Why aren't you basking?!
Cut through all the noise and build better, simpler Blazor web applications with Practical Blazor Components.Build Better Blazor Web Apps, Faster