(and how we are getting there)

Nope, not drilling for oil! However, having a good platform for rendering and serving our frontend in place definitely lubricates all the gears that make our organisation work efficiently.

In my previous story “Choking the Unicorn” I’ve described how you can start with removing the pressure on a monolith to grow to a Service Oriented Architecture with a more atomic design, promoting ownership and stimulating quality and speed in delivery. This isn’t something that you always need to do, but rather something that occurs when you scale-up your development rapidly. More on that in “Scale fast effect (Practical implications of Conway’s law)”.

To know how to get somewhere, you need to know where you are.

Let me briefly take you on a trip to bring you to where we are today, so I can explain to you where we are going tomorrow.

Phase 1: Prove value

We’ve started off with an off the shelve E-commerce application. Some tweaking here and there made it our own identity. It allowed for our organisation to embrace E-commerce as part of our core business while setting up the physical infrastructure to make it work. In this stage we are still with relatively few people / applications / stakeholders. Having everything in one spot just makes a lot of sense.

Soon opportunities arose and features needed to be added. The pressure of having one recognisable identity increased and we recognised that we should define and re-use visual components in our frontend for maintainability. At that stage we decided to rework the frontend and start with a design system, on which we still iterate today. The orange dots in the image show where we’ve started to make changes.

Phase 2: Reuse components

Once we understood we have to reuse and define visual components, we’ve started to develop them in VUE, a technical framework to isolate functional pieces. These pieces became distributed over multiple teams, but they still had to be mounted in — and maintained at — the old monolithic structure. The blue line here shows that we are talking about a different responsibility in code (frontend components are there for visuals but nothing else really).

The orange line was the next cut we’ve started to make. Trimming functionalities away from the current solution. There’s simply too much responsibility in the application and it doesn’t scale well. There are many teams working on that one thing, and it became a hotspot where code is overwritten, releases needed to be timed and no sense of ownership or quality assurance was to be found. That’s not an accusation though, it’s a consequence of how the software is structured.

Phase 3: Isolate features

We’ve started to add features, but chose not to add them to the current setup. Each change we make to our solution goes with the same question. What would the effort be if we separated this into a service? To reduce the risk of overcomplicating things, we choose to prepare ourselves rather than make moves bigger than life. Small iterations and learn. Sometimes this means that a service can be done from the ground up, but often this also means that the service leverages functionality from the monolith. That’s a good thing though, we can learn about what we really need and use, and how we think the future should look like without becoming completely reliant on something we don’t (yet) fully feel confident with.

Now that features are moved outside of the monolith and components are moved into separate libraries, we come to the next bottleneck. The more features we transition the less the monolith is able to render them. See, VUE is a Javascript technology, and front-end / template rendering is a capability on its own. The demand changed and improving the monolith in this aspect doesn’t make a whole lot of sense. I’ve written an article on how to do this in a way that doesn’t require a big investment, while gaining immediate SEO and performance benefit in “Chocking the unicorn (safely separating the frontend from the monolith)”

Phase 4: Move the responsibility of front-end rendering

Traditionally E-commerce platforms take on all parts of the technical challenge. They solve the business logic, store the master data, keep track of a user state, provide management interfaces, render templates and so fort and so forth.

In this phase we remove the head (rendering templates) and isolate it. By doing this we’ve set ourselves up for excellence on this (very specific) piece of the puzzle. We enabled ourselves to achieve extreme SEO performance, reduce load times on the client and understand which data flows between our monolith and this new frontend, so we can progress more easily and more clearly into our Service Oriented Architecture.

At this stage, we attempt to relay more and more business logic towards our services, but our services still leverage the monolith for some critical functions. We work on a daily base to reduce the dependency on the monolith from a frontend perspective. The more we reduce the dependency, the more performant our solution, as well as our teams become.

However, we introduce a new hotspot. All teams now have to develop their frontend features in that one environment. The orange scribbles in the image are indicative that we need to split this environment — again — into smaller pieces.

Phase 5 (This is where we are): There’s oil! Now build the platform

We’ve verified that we are on the right track, but a new bottleneck arrises. As a team, you can’t take responsibility for software that’s adjusted by other teams as well.

Also, working in such a big organisation makes it impossible to keep up with all changes and policies. Especially when your organisation stimulates intrapreneurs to innovate and promotes self steering teams. The freedom is awesome, but often you just want to have to bother about your own little island to work at without having to bother with the stuff of other teams and a clear integration plane where you connect with the rest of the organisation.

What we want is clear boundaries of responsibility and integration.

And that’s what we’ll need to provide. We’ve now already implemented some pieces of the customer journey into this one big Nuxt repository and the backlog is growing. It’s time to isolate these projects (pieces of the customer journey) into their own repo’s.

By having a repo per project, the commit log becomes clean and readable again. The repo’s not bothered by all the changes of other teams and they are interchangeable between teams. That way when complexity rises in one of the repos and the team is overly occupied with it, they can safely hand over another repo to another team and spread the workload. The isolation stimulates ownership as well, because in one big repo you don’t feel responsible for stuff that’s changed by everyone, but smaller repo’s are more easy to maintain and keep track off. This puts focus back on quality.

In order to do that, we’ll need a clear definition of the structure of these repositories and a way they interface with each other. After all, you’ll have to bundle, test and deploy them together.

That’s the start of the need for a platform, right there.

Platform: ‘a raised level surface on which people or things can stand.’

That’s the definition of a platform. And that’s exactly what it is. A stable surface of code, that does some of the heavy lifting for all the things that are standing on top of it.

Because all the projects have to be combined to work well together, we’ll have to introduce some complexity in this single spot, in order for all the projects to become less complex themselves.

Let’s have a look what you might expect in that platform:

tests (!)

a mount of the default components

information for connecting to the appropriate upstream (the monolith in case we hit a page that we haven’t moved over to the new solution yet)

default logging, metric collection and a uniform way to connect to the microservice landscape

default pipeline that rejects or accepts for deployment

standard scripting to do the bundling, health checks and other infra-related work.

New complexities

By moving all these factors into a platform (and therefore reducing complexities in project repositories), we inherently create new complexities.

How does the code work together once combined?

How do e.g. components still impact the projects (and therefore potentially break the promise of autonomy and risk-free collaboration)

How is behaviour integrally tested and assured

If one platform combines all to become one before it is able to run, how will this impact performance, in particular for the development process?

Which abilities should be relayed to projects, and which are at platform level?

It’s a balancing trick to only start a migration to a platform (that inherently comes with these complexities) once you’ve proven the value of this way of working and the reward outweighs the cost of overcoming these complexities.