The journey towards Restful & Full-Stack Engineering
“Full-Stack” is a loaded term these days. In its most fundamental form, a full stack application has both a frontend and backend that interact closely to produce a complete user experience. GeeksforGeeks describes a full stack developer as someone who can not only code a functioning frontend, backend, and create the database, but also as someone who “has the ability to design complete web applications and websites.” That is the loaded phrase. It is loaded because going into 2021, there are more options available than ever on how to build a functioning app that operates well.
This blog loosely follows up on an introductory blog post that describes a first attempt of this app: the online school for online schoolers. It “loosely” follows up because one week into the next round of development of this app, the whole trajectory took a hard left. This blog describes that technical decision, the reasoning behind it, and its cascading impacts throughout the entire app. Fortunately for the junior developers that this team consisted of, that decision would shape a much more worthwhile project and a new way of approaching product development as a whole.
Q1: Do you know what’s out there?
A major challenge as a junior in any field is that your depth and breadth of experience are usually not enough for making well-rounded authoritative decisions. This cannot be avoided and is why studying and experimenting are so important in the early stages. Coding, like many other disciplines, requires time to master and patience to handle. It can be very tempting to choose the easy route and build what you know will yield immediate results with little fuss or extra effort. Sometimes this is the only feasible option under time or resource constraints. To avoid building something rushed and poorly planned however, it is critical to consider what you might actually be overlooking in the early planning phases.
The first version of the Reach LMS app utilized a Java backend with a React.js frontend and a heavily “leaned into” redux state management for all data transfer within the tri-user interface. Redux was a natural choice given the potential size of the app, where admins controlled the input and flow of programs that contained courses, and courses that contained modules. Teachers could alter content while students could only view content in version 1.0. The way that the content was structured in a hierarchy, as well as the hierarchy of the users themselves, deeply influenced the first design. With the combination of this mindset and redux, the instinct arose to route content in a nested manner as well as the privileges of certain users throughout the app. The great “Russian Doll” app was born, where one level could only be accessed by another and the frontend completely rendered all backend information each time. It wouldn’t earn this nickname fully until it was completely deconstructed and refactored at a later date, providing insight into the truly entangled early user flow.
Q2: Is there a better way?
Protocol, protocol, protocol. In a high stakes production environment, it isn’t likely that a team will be able to deviate much from the plan or afford many mistakes. In an online school environment where the stakes are low to practice, the opportunity is still there to take some risks. Fully cognizant of the time constraints for this second round (four weeks), and aware of the goals from version 1.0 to operate under low-wifi and variable hardware conditions, a question was proposed multiple times in the first week. Did we get anything right in version 1.0? With a Java backend and React.js frontend as requirements for the project, our lateral decision making seemed limited. There were already issues apparent with the frontend mainly regarding certain “problem” components that had accumulated an excess of dependence on redux and were running so many functions that they were like mini hubs of overactivity throughout the entire app. Needless to say, they were slow.
Q3: Is the right captain on the right ship?
Q4: Is up down?
Frontend drives the demand for data in the typical user flow and the backend complies. It is rare that this dynamic is even questioned in the fast app development world. Truthfully, why would it be? The user is the one in control and should be given the most options in the most convenient manner, constantly. But what if they don’t need every option? After a few days of carefully examining what version 1.0 had become, a Russian doll with little of the efficiency that had first been planned on and even less of the intuitiveness for an ultra lite app, redux started looking less like a productive facilitator, and more like a burden that our app had to carry through every second of its life. Luckily, there actually was another way.
Q5: What will it cost?
The breakthrough came from one member of the team already leading the charge on the backend, who stumbled upon something unfortunately called the “HATEOAS” or Hypermedia as the Engine of Application State network application architecture. As stated unassumingly on the docs:
“Spring HATEOAS provides some APIs to ease creating REST representations that follow the HATEOAS principle when working with Spring and especially Spring MVC. The core problem it tries to address is link creation and representation assembly.”
What wasn’t clear at first but became obvious very quickly is that this wasn’t the same design. In fact, the concept of links pointing directly to controller methods seemed to already shift the delicate balance of power significantly more towards the Java backend through Spring. After examining some of the sample components built out in this new architectural structure, it appeared that the links were going to disrupt the frontend to such an extent that it would render redux virtually useless. Redux was indeed rendered virtually useless.
Q6: Is the app prepared to shift control?
Implementing a structured design like HATEOAS with a React.js frontend implies that the team has some clear idea of what to do on the frontend. Initially the frontend design seemed completely clear, but as the total refactoring of the backend and frontend simultaneously took place, additional possibilities crept up that demanded rethinking. For example, adding teachers and students to a specific course. Previously this functionality was built out on the frontend using separated search bars on the course management dashboard. Being both awkward and clunky, these search bars were quickly removed in round two and replaced with a modal form, as were most other actions throughout the app. What HATEOAS allows for is the compartmentalization of data on the backend such that what you are linking to on the frontend is only what you need in that specific moment. Whereas before the frontend was making standard API calls to generalized endpoints such as: “/allusers” and manipulating the data out of it using redux, now it was calling very specific endpoints via links that would render all of the teachers enrolled in a specific course from the backend directly. The middleman had been effectively cut out.
Q7: What does the user see?
In effect, the structure of HATEOAS greatly unburdened the frontend through the creation of Rest Entities that actually handled the data calls themselves and did much of the heavy lifting for data transfer throughout the app. Calling data on the frontend became more of a precision art and knowing which links to place where. The frontend components were reduced in code by at least 30–50% on average, and became more like stylized shells for the structured entities to do their work. New components were created to render individual and list level data that were custom named singletons and lists within the app. This gave a standardized framework for how each dashboard would handle its user interface, actions, and the atomic rendering of data. The initial Russian doll structure had been completely inverted for a modular and decentralized approach that would now future-proof the app for further development ambitions.
Q8: Does the app have what it takes?
In today’s economy, efficiency and standardization matter towards scaling up operations to meet global demand. This decision made the application significantly faster on the frontend and more towards the ideal ultra lite app that had been originally envisioned. By taking all options into consideration, the team was able to construct something more ideal and distinctive than the quick application that was constructed before. Now the path towards greater functionality is clear for future developers working on this codebase, and the initial time invested to learn these new tools and implement them can pay off. The structure is in place and most alterations going forward will be plug and play. The main takeaway here is that a little ingenuity and foresight can take a short-term project a lot further than relaxing into a predictable pattern that may not actually serve your users in the long-run.
For further insights into building applications with HATEOAS and React.js see these resources: