Sunday, 10 November 2024

Project 2 - Simplest SAAS - Service Scaffolding

 In this post I'll discuss how I intend to scaffold the article site SAAS so that I can build out the key features without having to worry about integration with back-end services.

The basic idea here will be to take a layered approach, and use an implementation of the Service Layer pattern to encapsulate all of the core business functions of the site.  There will be services responsible for each of the key features of the site - one for user management, one for article management etc.  Services will act as mediators between the Vue components and and back-end logic. The Vue components in the site will only interact with these services and will  never interact directly with a back-end provider.

In addition I will use the Dependency Injection pattern to construct these services.  Where one of these logical service has a dependency on a high layer,  a typescript Interface will be used to define the operations of that layer, and the service will be constructed with a class that implements that interface. 

The Dependency Injection pattern makes it possible to swap different implementations of the service dependencies without requiring the service to be modified.  The Vue components are isolated from any changes to how the back-end dependencies are written,

This in-turn will enable me to create in-memory, scaffolded versions of these key dependencies (user auth, persistence, payment etc)  to get the site running, then enable me to swap to actual implementations with minimal work.  This has the nice advantage of enabling back-end services to be swapped out without affecting the user interface. For example, with this approach I can potentially switch between database host providers minimal impact on the UI. It also simplifies testing - the services can be tested with mocked or faked versions of dependencies if required.

For working with persistent data,  the Repository pattern is often used with Dependency Injection.  A Repository is a specialised service dependency that abstracts all persistence (database) operations behind a well-defined interface - which is exactly what we want!

Here is an example of how this will work for the design requirement of providing the user with a list of the articles that they own.    

  1. The List Articles page (a Vue component) will invoke the get_user_articles() method that is defined on the Article Service.
  2. The Article service will be constructed with an instance of a class that implements the IArticleRepository interface. This interface also defines a get_user_articles() method 
  3. There can be multiple classes that implement this interface.  Any of them can be chosen at design time to construct the service
  4. Initially, I will use an Repository implementation that uses a simple in-memory store to persist user articles (this will reset every time the site is started).  Eventually I will replace this with a Repository implementation that uses a hosted database.
  5. The List Articles page doesn't care which implementation of IArticleRepository is used. It only interacts with the Article Service, and the behaviour of this service never changes. 
  6. This means that the List Articles page can be safely built to work with a simple in-memory implementation of the repository, and no changes to this component will be required when the Article Service is swapped to using a repository implementation that works with a  hosted database



One other thing I should also mention is that the data types that are sent to and from the the dependent layers should also be defined. This enables a type safe definition of each interface.  For the example above, as well as defining the IArticleRepository interface, we should also define an Article type for the repository to return.  These data types can be thought of as the Models in our design.

Using this approach takes some initial set up but I believe that it will pay significant dividends in enabling me to set up a fully featured user interface without having to worry about the complexities of integrating back-end services. I can focus on implementing the core features of the site first and save significant time on my first few iterations.

Big desk and a tiny win

I looked at my desk today and didn't like what I saw.  My desk is two-tier IKEA behemoth that I have had for nearly 20 years - it is sup...