A year ago I was picked up by a local development consultancy, Callibrity Solutions, LLC., and placed on their Crossroads Church account. At the start of my time at Crossroads, the tech stack consisted of AngularJS/Angular for the frontend, C# for the backend, and PHP for the CMS. Not a whole lot has changed over the last year, and a lot has changed over the last year. When I first started at Crossroads the entire frontend was written in AngularJS. I was put on a feature in which they were refreshing their live stream page and they wanted to attempt to create a hybrid app that was running AngularJS and Angular side by side. At the end of the feature work, we had attempted the hybrid app (all while Angular 2 was still in release candidate), found that it broke our automation test suite, and fell back on writing it all in AngularJS.
The result of this was a decision by architecture to try and create a “Microclient” architecture that would allow multiple discrete applications to be built on different front end technologies (Angular/React/etc.) and function as different parts of the same domain, e.g. /live and /groups could be two different applications running different technologies, but still be served under the same top level domain, www.crossroads.net.
To accomplish this we turned to Phoenix, the Elixir web framework. Really, any MVC styled framework could have provided us the functionality we needed for this project, but having one team member with Elixir/Phoenix experience on the team swayed us toward Phoenix.
The basic idea is not a new one, I think. Essentially Phoenix is functioning like a glorified router and as requests come in for different portions of the site, the assets are sent back to the browser and the JS framework boots up. For example, right now on www.crossroads.net, /live is an AngularJS application responsible for displaying live stream content of church services. As of this writing, /connect is an Angular2 application responsible for enabling church members to connect with each other. Once a user enters one of these two applications, the Angular router takes responsibility for routing within the specific application. When a request is made for a route that isn’t contained within the app that is running in the browser, the request gets pushed to the Phoenix application where the route gets matched in the Phoenix router and the necessary assets are sent back to the browser to load up another individual, complete application.
So what did we gain with this approach? Firstly, we now have a feasible upgrade path for the legacy application. Before the microclient solution, if we wanted to update our Angular 1.5 code to Angular 2, it would have had to be a full system overhaul. Feature work would have had to be put on hold while the whole application was updated. This was a deal breaker for the Crossroads organization. By creating the microclient architecture, portions of the site can be broken out, written in a newer version of the technology we are using, and deployed without bringing down other parts of the site. This is a huge win.
Second, we are free to use the right tool for the feature. Not all features are created equally, and some feature work requests functionality in which the current tech stack may be difficult or not possible to implement. We can now leverage technologies that are better suited to the requested functionality in a given portion of the site without having to poorly kludge something together in an ill suited language.
Finally, we reduce merge conflicts, and by extension, team conflicts in our day to day work. Breaking out portions of the site into their own independent applications means developers and testers are free to develop a feature largely in isolation from the rest of the team. I don’t think I need to elaborate on why this is considered a huge win.
While the benefits received from moving toward this architecture are huge (at least big enough for us to stay with this design choice), the decision to move toward a microclient architecture did not come without tradeoffs.
System complexity has increased considerably. Drawing a sketch of the architecture of our project onto a whiteboard results in a rather labyrinthine illustration. There are a lot of moving parts and it is not always easy to intuit what part of the system is responsible for what. However, the day to day work done by a developer rarely touches on these complicated parts of the system. This results in relatively low overhead for new developers on the team. Generally, all a new developer would have to do is clone and build the Phoenix project, clone and build the feature project, symlink the assets folder of the feature project into the Phoenix project, and they are ready to develop. In spite of that, bugs still creep up and it can be difficult to pinpoint exactly from where the bug originates.
Have we made the right choice? There will always be the lurking question of whether or not we made the correct choice. So far the answer to that question has been yes. We created something that should provide us with the greatest flexibility both now and into the future. However, there is always the possibility that we somehow unintentionally painted ourselves into a corner. We are getting ready to implement a Digital Experience Platform (DXP) solution into our product to deliver custom content to our users. While we do not anticipate this being the case, it is always a possibility that the manner in which we’ve designed our system will be incompatible with the DXP solution we pick.
Thankfully, the Crossroads organization holds an attitude of falling forward and we are encouraged to be ambitious, even if that ultimately results in failure. We regularly inspect our successes and failures and take learnings from them to improve people, process, and product. Sometimes that means continuing with the direction we are going, sometimes it means changing course a little, and sometimes it means abandoning ship and going a different direction.
In the end, the last year at Crossroads has proven an exciting one with engaging challenges and substantial organizational growth, both in personnel and technical savvy. As we move forward in our efforts to build a quality product, we will certainly have more opportunities for growth and challenge.