Search code examples
javascriptangulararchitecturesolid-principles

Architecture pattern is an extreme violation of the open/closed principle


enter image description here

I am working on a web app that will automatically generate Bootstrap sites given a bounded set of parameters. I need help with regards to architectural decisions, as over time, I have made very naive design decisions and I don't want to repeat this mistake with this project. For my PoC, I have taken an MVC approach to design, with the top-level architecture (see above) containing the following:

  • CanvasComponent - this is the entry point for the application, a UI element in which the user can generate their website and be given to download it;

  • CanvasService - this service orchestrates the creation of the website, and has dependencies on a set of services (NavbarService, HeroService, FooterService);

  • DomService - this service is in charge of the creation of the DOM element at a high level sans styles;

  • ComponentService - these group of services (NavbarService, HeroService, FooterService) are in charge of the creation of the DOM element at a lower level;

  • FontService - this service is a Google font repository.

The above is something I put together fairly quickly, so I understand that it isn't perfect. I also have a few questions with regards to the direction of the project with regards to the scalability of it as I move towards productionalising it. These are my problems:

  1. I showed it to someone and they said they can't make sense of it... as it sounds like my CanvasService, DomService and component services create raw HTML, all of which are models that describe DOM elements. It seems very overly mis-engineered. the way we are developing our services isn't scaleable or manageable. If nothing else, it is an extreme violation of the open/closed principle. They will ultimately be huge "factories" that don't fully cover all the functionality of DOM elements. This is my main concern. How do I resolve this from an architectural perspective?

  2. Given the nature of the project, I am dealing quite extensively with raw html. I use a mixture of approaches to dynamically generate the required HTML. I wanted to ask if the above is advisable. What would be the cleanest approach architecturally to creating and managing blocks of HTML? Should I use raw string or create something more bespoke?

  3. What would be the best approach to storing an assortment of styles per component (navbar, hero, footer) and then applying them randomly? From what I understand a style can be separated into two categories - a template and a theme. A template can have many themes, and a single theme can be associated with multiple themes. A good example is "light/dark" colour mode on a website. At the moment in NavbarService, I store a range of possible widths and heights in an array.

  4. Are there any issues that my current architectural approach will present down the road besides the violation of the open closed principle (unknown unknowns)? In the past, whenever I have started projects like this, they have quickly become unsustainable. I lose interest, because I am wrestling with the code-base at that point. I want the process to continue to be enjoyable, and keep my code clean and manageable over the course of the project, as well as apply the best principles.

A sample demo is available here: https://stackblitz.com/edit/angular-ivy-2pga8q (each time you reload the page, a new navbar appears).


Solution

  • This is an interesting problem. I also didn't quite understand the diagram but your description makes more sense.

    Let's assume for a minute your generated HTML/CSS/JS components are sensibly written and generate reasonably formatted and sensible output. At this point you don't really 'need' to store meta-data about it as anything will be un-required bloat. What you will need is the ability to construct small, modular blocks of code that can be recompiled again after editing or additional input parameters.

    To support this I strongly suggest separating the output of the code (HTML) as a version-stamped solution library - and the code that generated that should be a collection of marked-up data from user or data inputs.

    To create a simple analogy imagine the formula (8+1+1=10).

    In this example the output (10) is the only thing you need to publish/present/store. However you need to keep the starting data (8+1+1) independent - primarily because if one of those values changes (say it's now 8+2+1) you can now re-generate a second version of the output with a new version and get a new answer (11).

    As such I'd focus a LOT more on storing the the building blocks/wysiwyg/mark up components than worrying about the string/text format of the output elements. From an architecture perspective if you have any ongoing need to interact/modify this code you need to focus on ease of use and re-usability.

    Remember also unless you're creating skynet you're not writing 'code that writes code'. You're writing code that assists humans in writing code. Always assume there will be need for intervention and modification from an outside source - focus on getting the modular form of (algorithm + input = output) and store the process and the inputs. If you get that right you can re-generate the outputs at any time for any reason.