facebook
MENU

Blog

Xento is a product based organisation with more than 800 IT Professionals including 350+ PHP Professionals working with a healthy dose of creativity and innovation. We promote an open atmosphere, where team members freely voice new ideas and are involved in all phases of our growth. At Xento, working is not just work; it's fun. Nurturing individual talent, fostering team work and recognition are the key elements of the Xento Culture.

Stuck with a “Mammoth” Monolithic code? Tame it the right way!

Category: Engineering, PHP Development

Monolith to Service

Application Code becomes mammoth size?

There is a classic pattern while building successful products. Initially, it’s a relatively tightly focused, designed to fit a specific and well-defined need or interconnected set of needs. When it’s released, it’s great, gets widely used and everyone’s happy. Part of its success is its tight focus. But success breeds opportunity, so new tools, features, and functionality get added. In the classic pattern, these additions extend the same codebase and the application grows.

Each addition to the codebase, each new feature, adds to the complexity of the system and increases its fragility. A simple addition — to patch a security issue, for example — can cause a major headache for fear of cascading knock-on effects and trickle-down impacts. Making upgrades to a part of the system just amplifies the problem. There are delays adding them and pushing them out to a production environment where, especially in the need of security patches, they’re much needed.


Large systems on singular codebases like this are often called MONOLITHS. Our tiny product too, over the years, became THE MONOLITH.

tiny but monolith product an overhead

 

Old Tech Stack

  • A single code base for all the products, version-controlled by SVN.
  • Custom made PHP Framework called FuseApp. Basically it’s just a router and nothing more.
  • PHP 7 as both server-side and client-side, ie Core PHP & SMARTY as template engine. Also, over the period a lot of business logic crept into SMARTY files.
  • No dev production parity, meaning we were using XAMPP on dev machines and a completely different set for production.
  • No dependency management. We maintained the FOSS libraries we use.
  • Tons of violations of design principles. No separation of concerns at all, business logic scattered all over in controllers, models, views, and database stored procs as well.
  • As you can figure out by now, our system is a tightly integrated monolith, and hence change management and maintainability were a living hell.

 

Gearing up

team efforts to decouple using 12factor App and solid principle

We decided to decouple our application using the guidelines laid by The Twelve-Factor App, Martin Flower, and SOLIDprinciples. We decided to migrate organically ( Go Macro First, then Micro ) as it’s not feasible to migrate the entire 100 plus subproducts all at a once to the service layer. Our first task was to narrow down to that handful of mature and stable sub-products to conduct this change. Once that is figured out we,

  • Detached frontend and backend as separate Apps: The first decision was to rewrite the entire UI/UX to React ( with Redux ). All the interactions between frontend and backend got rewritten to REST API calls with JSON format as the payload for Request and Response. This decision to detach the front end was a complete success. Since we started developing the new features with the services approach, we could incorporate new developers to the team who were not PHPspecialists. In fact, we’re developing on javascript now! Plus, they don’t have to understand the whole picture of the application logic. They just need to know what are the responsibilities of the services and what dataset they need to get that done. So, having new developers on the team suddenly became an easy task.
  • Codebase: Only one codebase per App, tracked in Git but many deploys. Deploy is a running instance of the app. This is typically a production site, and one or more staging sites. Additionally, every developer has a copy of the app running in their local development environment, each of which also qualifies as a deploy. The codebase is the same across all deploys, although different versions may be active in each deploy. For example, a developer has some commits not yet deployed to staging; staging has some commits not yet deployed to production. But they all share the same codebase, thus making them identifiable as different deploys of the same app.
  • Upgraded from PHP 7 to PHP 7.2: We kept PHP for the application logic ( kudos for Our deep-rooted love for PHP ). We have migrated to PHP 7.2 mainly because it offers better performance and Libsodium as a Part of the Core.
  • Migrated from FuseApp to Slim: Because of its tiny footprint, SLIM is one of the fastest frameworks bench-marked by various renowned authors. In addition to this, we can implement the route cache, which will improve the performance of big projects. Slim supports all native HTTP methods ( GET, POST, PUT, DELETE, etc.). The Slim framework uses PSR standards, and hence it’s extensible because we can replace the core components of slim with our custom ones or with any other vendors( which follows PSR standards ) and still our project will continue to work without any issues.
  • Dependencies: For the front end, we are using Yarn as a dependency manager for FOSS packages and Monorepo to host and share our common React components across the products. For the application side, we use composer for FOSS packages and Satis private repo for hosting our private packages. One benefit of an explicit dependency declaration is that it simplifies setup for developers new to the app. The new developer can check out the app’s codebase onto their development machine, requiring only the language runtime and dependency manager installed as prerequisites. They will be able to set up everything needed to run the app’s code with a deterministic build command. For example, the build command for PHP is composer install, while for Javascript/ React side it is yarn install.
  • Dev/prod parity: Our developers were using XAMPP on their Windows desktop. Now we have spun up a Vagrant box for them using the exact salt stack we use for production. So we have mirrored our production environments by providing the same operating system, packages, users, and configurations, all while giving developers the flexibility to use their favorite editor, IDE, and browser.
  • Separation of config from code: We have separated App’s config i.e. everything that is likely to vary between deploys (staging, production, developer environments, etc) from code. This includes: Resource handles to the database, RabbitMQ, Credentials to external services such as Amazon S3, and other backing services. We store these configs on a separate repo where developers don’t have access to and we have configured our CI pipeline to inject the appropriate configs ( based on deploys – staging, production ) as environment variables to the server.
  • APM: We use New Relic APM to retrospect our Apps performance and health.

    Application monitoring using NewRelic tool

  • Treated logs as event streams: Our App never concerns itself with routing or storage of its output stream. We use Papertrail to aggregate all your logs (Syslog, Text log files, Windows events, Apache, etc ). No more digging through a dozen log files and directories.

    aggressive logging-usingpapertrail-on-cloud

  • Enhanced Application Logic: We put Our Big Fat Controllers on the weight shedding program 😜 . Meaning after a lot of work out ( Thanks to SOLID principles ), we toned it down to super slim controllers. All the application businesses have been migrated to Business Objects backed by a Repository pattern for transacting with the database. Also, all the interaction with external systems got rewritten to RESTful API calls. We are using RabbitMQ for async processing, Redis for data caching, and avoiding sticky sessions. Our Apps by default are stateless and share-nothing. Any data that needs to be persisted is stored in a stateful backing service(PostgreSQL database ).

 

What Next?

Our migration from a Monolith to SOA has been a great success. We want to stop here and wait for the appropriate use case and businesses need to move to microservices. Because migrating to microservices can end up in,

replace-macro-to-micro-service-with-tools-and-coding-approach

Author: Author Abin Thomas is the Associate Director - Development and with Xento from more than 10 Years, Find more detail about him here on this page Abin Thomas