Dec 5, 2020

- 8 min read

How I moved from a monolithic development style to embracing microservices

How I moved from a monolithic development style to embracing microservices

Alan Redzepagic

How I moved from a monolithic development style to embracing microservices

Moving from a monolithic WordPress stack to microservices architecture with Nuxt, Vuetify and WP API.

After a long time developing web sites with open source CMS and being influenced by recent developments in the JavaScript world I decided to upgrade my development workflow and production stack. I’ll start with describing the production stack I have been using and moving to a new stack, examining the positive and negative traits of both.

Long story short, I converted my existing WordPress stack to serve as REST API to feed decoupled front-end in Vue.

Part 1. What have I been using in the past?

  • In short: VPS, CentOS, Apache, MySQL, PHP, cPanel/WHM, WP, Premium Themes

Infrastructure

For more than 10 years, I was relying on cPanel/WHM stack to provide a full set of web hosting services for my web development clients.

I was using various hosting companies like Rackspace, ServInt, and Contabo. More recently, I started using cloud services like AWS and Heroku. Renting servers or assembling the infrastructure was never approachable. Running WHM, once all quirks have been worked out, does not need much attention, except for regular updates and systems migration. Some unexpected time was dedicated during traffic spikes or security related issues around public libraries.

Since this was a “one-man-show” and since the ecosystem gave rise to pretty sophisticated licensed or open source themes and frameworks, the decision was made to leverage the benefits of affordably outsourced “heavy-lifting” in back-end development.

While focusing on overall UX and building on top of CSS frameworks with modular UI elements, custom logic could be built with Type Systems and raw PHP as Plugins and theme core extensions.

Back-end

The first step was to consider vertical compatibility between OS features and services in favor of application requirements. My choice for production ready stack in most situations was RedHat/CentOS. The second part and my tool of choice was Web Host Manager (WHM). Initial configuration is for basic usage including updates, backups and monitoring. After deploying working apps, more fine tuning was done for PHP, Apache, MySQL, and DNS. For security best practices and sometimes paranoid level of protection, I used tools like CSF, LFD, CXS, etc.. Two major benefits of this approach is metering of hostile IP’s/subnets and protection even if zero day vulnerabilities were found in application level, which PHP software had a fair amount in the last 10 years. I have to mention that MySQL played a big role and tools like SQLyog helped to get insights for fine tuning.

With extensive testing and feedback from real world situations, the stack was optimized to deal with much higher load than expected and retaining a high grade of security in much needed environment.

Pros: With a big percentage of unused code processed on the server and delivered to clients, various PHP caching and optimization techniques were used, like HTML/CSS/JS Minification, Concatenation, Deferred loading. Together with good optimization of Apache and MySQL, stack was tuned to deliver impressive performance on modest servers.

Cons: Scalability is limited to vertical scaling only, due to the nature of how WHM works.

Debugging issues throughout the stack can often be time consuming because of multiple layers of security.

At the time of the beginning of this stack, mobile internet was not a thing and desktops and laptops were quite capable of running websites with overhead code. Users came from fixed internet access with stable latency. After a period of mobile growth taking the majority of web traffic, responsive design was introduced and added more code overhead. Together with low media optimization and advertising practices, mobile experience at the time was in a bad state.

Front-end

I have been developing and researching client side solutions, making suitable decisions for project requirements. Rigorous testing was done for performance, UI/UX features, and back-end development experience. Also a major role in decision making involved the evaluation of open source projects behind the tools being used or commercial tools under licence. All of this was done to ensure a long lived product.

When all of the details mentioned above checked out, developing a user interface and custom business logic (as custom themes or building on top of premium themes) was usually a breeze and allowed for fast iterations from development to production.

All modifications and custom logic was done within specifications of a well tested stack at this point.

Pros: Building on top of premium themes with opinionated, premade UI elements and well defined and tested frameworks is a huge time saver!

Cons: These premade themes often have a decent amount of overhead code since it is oriented for general purpose use cases. Resolving front-end bugs because of JS incompatibilities introduced by code from various developers is highly time consuming.

Conclusion

This approach allowed one person to vertically control the stack, develop and deliver very fast modern products from a secure environment. Also I was being able to provide cutting edge features, stability and high performance for a variety of clients and security implication they bring.

Part 2. What I have moved onto?

  • In short: AWS, EC2, Linux2, Docker, NginX, NodeJS, Vue, Nuxt, WP API, GraphQL

Development stack: VScode, Github, TravisCI, EC2

I have started developing javascript single page applications with server side rendering and support for requesting and parsing external APIs. Generally, on landing pages, server side rendering is done with NodeJS behind NginX reverse SSL proxy with HTTP2 support.

While experimenting, I developed an app that is hosted on EC2 and fetches data from 3 different APIs and utilizes a CDN. I developed the following back end services to support the app:

  • Portfolio WP REST API, WordPress instance on cPanel VPS.
  • Currency Exchange REST API, Dockerized Python app on EC2.
  • News WP REST API, WordPress instance on cPanel VPS.
  • Media CDN, simple file hosting on cPanel VPS.

By adopting the above tools, I solved one of the downsides of the previous stack, which was scalability. With this kind of architecture, scaling is without boundaries if you include the option to expand with CDN, load balancers, static serving and autoscaling.

AWS example:

Enter Nuxt.JS

Major benefits of new client side features in Vue are built on top of and provided out of the box with Nuxt, allowing features like:

  • Universal/Isomorphic Application

By nature, JS single page applications fetch content after all parts or the shell of an app are loaded. This approach creates issues for search engines, since crawlers are expecting static HTML content. To solve this problem Nuxt can enable Universal Application mode which utilizes NodeJS to provide pre-rendered HTML content for any requested URL. For any subsequent request, only content API requests are made.

  • Per page code splitting

Usually, JS apps send code for all pages even though they are not used on a requested page. By utilizing Webpack, code can be separated for each page and sent just for requested page.

  • Progressive Web Apps (PWA)

PWA Nuxt modules provide full support for offline usage, notifications, device hardware access and other features creating user experience similar to native apps. With recent Chromium advancements, PWA can be installed directly from Chrome browser. Afterwards this app behaves as classic native application and can be installed on any device and OS.

  • Async components

For a large application, it is recommended to divide the app into smaller chunks and only load components on demand from the server.

Wrapping import in function will be used by Webpack as Promise to load parts of the code asynchronously.

  • Prefetching

Nuxt.js will automatically prefetch the code-splitted pages when visible in the viewport by default. After index page is loaded, second level page is lazy loaded and on standby for data fetch.

  • Device detection code split

Shipping code only for specific device type and OS type.

  • Offline detection

Simple network status notifications

  • Nuxt architecture

Conclusion

Comparing to the previous stack, the only downside is significantly longer development time which is only true in general use cases for small/medium enterprises.

The new stack provides blazing fast user experience. With SSR, Initial load is under a second. All subsequent loads with the help of service workers and well optimized API’s are around 50ms. For all returning users, the experience would feel native as the shell app is pulled from local cache and content preloaded from a persistent state. Fresh content from API and images from CDN will load and render under 400ms (Doherty’s Threshold), which is considered seamless interaction by human perception.

In short, this is a dream come true. Native experience delivered over the web with seamless updates using open source collaboration and technology.