The following is a post I wrote for the Ingenious team a few weeks ago. I wanted to give some guidance about what to expect in terms of tech decisions in the future. It is not that we haven't thought about this before, but the last time we did it was some years ago, and from there, we kept going with the flow. I took a step back and tried putting what I currently believe in this post.
We are a software development agency that helps to build Healthcare products using our own approach "Behavioral Design" based on Behavioral Economics concepts. For the sake of this post, you can think of Ingenious as a regular boutique development agency.
When I joined Ingenious, more than 6 years ago, the idea was to help the team shifting the technology foundations of the company, I ended up doing much more, but I want to focus on the technology side of things today. Back then, Ingenious was not Ingenious, but Ingenious Softworks and I found an amazing team of experienced .net developers.
Later, when the whole JS ecosystem blew off, we were already in a position to take advantage of it. We picked Ember as a frontend framework for My Fertility -they still use it- we also picked React for some early projects for Denver Health. It was official, we were making Single Page Applications, we still do them, but more importantly, we embraced the UI component model.
While this seems natural, at one point we decided -we Ingenious, we the developer community, this is a big we- that to be able to develop application UIs using components -this is, mixing together HTML, JS, and CSS in a single unit- it was necessary to create a new, separate application.
To a certain degree, this makes sense, when React -and every other framework came out- SSR was an optimization left out for later, for example, there was no way in Ember to do SSR when it first came out, neither React had one so it made sense to create its own application and communicate using JSON. Also, globally there was -still is- a trend around technology specialization. We never shared that vision that says that if I know the ins and outs of a certain technology, then I can be more productive with it and do more work in less time. I always thought that to deliver a feature, one should be able to work on both ends, even if that work is slower, it would be complete, and I hold to that belief today.
All those reasons, and probably many more lead us to believe we needed to choose between a single monolith that treats complex views as second class citizens, or specialized apps that can leverage React, or Ember, or Vue, but that cannot co-exist in that monolith, and that's simply not true. It was not true back when we made these choices, and it's definitely not true today.
In most of the cases, having multiple apps hurts productivity more than finding a way around the monolith and enhance it with JS. Having multiple apps generates a REST contract that needs to be held true for both ends, it creates the need to keep both apps in sync, it doesn't produce faster results, it generates stagnation and slower cycles since now there are at least two moving pieces, two codebases, two apps that can go down, two everything, that's 100% more problems.
That's not to say sometimes you need two applications, sometimes splitting is required, even mandatory -thinking about mobile apps here- and there's no way around those scenarios, but when there is, we should think things carefully.
In retrospective, I should have revised my decisions more carefully, I should have challenged the status quo more. Luckily, I have you that did a fantastic job regardless of those decisions.
Moving on, we should think if the benefits of doing what everybody else is doing will benefit the project, will help the team, but most importantly, if it will benefit the client.
My intention is not to categorically ban SPAs and React or Angular or Ember at the company, but to give you the chance to think about that part of the architecture more in-depth. This is me telling you that you can choose not to go with our standard approach, and this is me telling you that our standard approach may someday be not standard at all.
You may be thinking, ok if we should consider sticking with the monolith more closely how should we build UIs from now on, do we go back and ditch the component model? No, I don't want to do that either, I think that's a step back.
Luckily, other options put things in a nice middle ground. Some are more appealing, some feel dated, and some are new tech that we may consider using in the future.
Here I list some options I've found for the current technologies we use, there should be plenty more that I'm missing.
Rails has been our de-facto way for building backends at the company, and I think it will serve us for many more years. It has excellent features, and it's battle-tested. I think it also worth mention that Rails can do React or Angular, or Vue and some solutions even allow SSR and re-hydration.
Here's a list of things that we may reach out in the future:
- Rails Webpacker (does React, Vue, Elm, Svelte, Angular)
- React Rails (does SSR)
- Stimulus + Turbolinks
- Stimulus + Stimulus Reflect
- Stimulus + Turbolinks + NEW MAGIC 👇
Phoenix is a Rails like framework for the Elixir programming language. I won't enumerate the benefits of the functional approach elixir has, or how good the Erlang VM is, all that you can read elsewhere. The only thing that strikes me as I rethink best practices is that you can create nice interactive applications with it, you can mix presentation and behavior -ala React components- in structures called LiveComponents without needing to split your app.
How can Phoenix do this? It's not important for the sake of this discussion. The important thing is that you can create reusable components as monolith first-class citizens. The tradeoff is learning a new language with new paradigms, this is a tradeoff that we may be willing to do if we stick true to our previous learnings of having less moving pieces.
Blitz is a full-stack framework inspired by Ruby on Rails but written in React. It's based on Next.js and it can deploy itself as a fullstack application with a long process serving the app or in a serverless environment like AWS lambda or Vercel.
The promise is to keep writing React components, import server side code functions and call them as if they were in the client. Blitz takes care of translating that to API calls.
Ok, so this is all nice, but it's missing an actionable item, what to do next? I realize that you need certainty, not the half baked solution I just gave some paragraphs ago. Sadly, there's no silver bullet for developing software as there's no silver bullet that will fit all the projects we do at the company.
From Qt apps that read CT scans to huge backends in Rails to more serverless oriented architectures we have covered a lot of ground in software development, and we will continue to do so in the best way we can, and similar to today's post there will be new ones enumerating things we believed were right but ended up being wrong decisions.
For the moment, my current thinking is to try hard not to break the monolith unless it's absolutely necessary.
No much more to say other than, stay current, and stay focused in the tech that better solves our problems; this sometimes means no to jump in the next hype bandwagon.