If you're growing an online business, chances are you'll have to eventually grapple with managing and updating a complex mass of PHP code. Follow these 10 rules to get that app under control.
PHP picture from Shutterstock
The seemingly "normal" journey of any successful startup these days begins with a great idea and the caffeine infused code-at-all-hours-and-get-it-to-market origins of its founders.
It's what sets the startup dream apart — the allure of being yourself in "non-corporate", disrupting industries, strengthening the economy, working with other like-minded people and building great products to solve the real life problems that you believe in. It is awesome.
The founders that discover how to engineer their business past the nascent stage will continue building their team and maturing their product. Some take on funding, but most are likely to hear those paralysing words — "legacy app", "technical debt" and "rewrite".
These are my rules for making the least wrong decisions when evolving your original application, without taking down the business in the process.
Let's start with a few assumptions:
- You're hosting your app on your own physical server or VPS.
- You're using MySQL for your database, and it's starting to get BIG.
- Your PHP app has evolved over many years, developers and frameworks.
- You're using Git for SCM.
1. Get your head straight
Quite simply, your mindset will shape your thoughts, attitude, decisions and performance.
Remember that the original code grew the company to this point, and both the opportunity and challenge is in evolving the tech stack while providing customer value.
Get to a point of decision as fast as possible. Focus on being objective, with the aim of building the rationale of your thoughts and decisions to move actions forward.
2. Get everyone on board
If there isn't a genuine understanding and commitment by everyone to evolve your tech stack, it will be no different to any other half started project.
As an engineer, it's your responsibility to share the context and help others understand the "whys". Work out your elevator pitch so that you can clearly explain the value proposition of refactoring or rewriting. Think about it from the point of view of your customers, founders, sales, support and engineering team.
3. Be emotionally intelligent
We've all been there — all worked up over something seemingly very important at the time, only to realise that it really didn't matter in retrospect.
Be sure that you take a step back every now and then, and look at the bigger picture. Sometimes near enough, is actually good enough — software is evolutionary after all.
Everyone has opinions, but remember to be a team player — it's better to commit to something as a team, than talk about it for weeks as individuals, with no outcome in sight.
4. Ask lots of questions to prioritise and plan your tactics
At hipages, we have 4 distinct applications: the consumer site, the tradies site and two iOS apps.
Asking a lot of questions in my first 30 days helped provide me with the clarity needed to make meaningful decisions, in what was a new landscape for me. I encourage you to do the same, the more questions the better.
5. Find a small win, and execute it perfectly
Pick one thing to migrate to a new platform. Have a clear hypothesis that can be validated, and build confidence for you and your team. Set out breakpoints for review along the way, and if needed rollback or exit from the strategy.
In the case of a large PHP application, there are usually at least three discrete functions which can be moved out as standalone, or rewritten as such. You could create a new repo, push your code into it, refactor and deploy it as a service outside of your app. A small EC2 instance might be good enough to host it.
6. Evolve, not rewrite
Most startups cannot afford to stop providing customer and company value, to rebuild or rewrite their stack.
Software evolution happens all the time, and can be driven by changes in user needs, technological advances, innovation and disruption. We sometimes call this new feature requests (NFR) and business and usual (BAU) work.
In the same way there are rules for evolving a product over time, we should have rules for evolving the technology stack. You'll need to create them with your team, company and product in mind. Here are some examples:
- Port or rewrite an existing feature as a standalone stateless application, and use a reverse proxy to dynamically switch between old and new apps based on URI. You'll probably need a shared session management service for this.
- In the scenario that there are 2 distinct products in your application (eg consumer app and admin app), clone your repo so that you have 2 identical repos. Rename one as consumer app, and the other as admin app. Systematically carve away at the code until you have 2 distinctly different apps, forked from the same code base. You can move shared code to its own repo, and use a package manager to bring it together.
- Start a new app from scratch, and "encapsulate" your legacy code within it. Move routing to the new app. Implement new features in the new app, deprecate old ones by switching the route within the app. This could be useful for old code bases with many frameworks and competing software patterns wedged inside it, or old "black box code".
- Deprecate as much code as possible. The smaller and cleaner the codebase, the easier it will be refactor, replace and test.
7. Innovate at least three things
As important as it is to continuously improve your tech stack, find a way to innovate as you're evolving — it generates value, and they'll love you for it.
It could be a new feature for your customers, a new "enabling" technology for your team, or coming up with a new way to solve an existing problem. Intra-company hackathons could be a great way to spark the creative thinking needed to innovate.
8. Small micro applications and services
A lot can be said for splitting up your application into a number of single function services, and associated micro applications. If done right, they can be easier to test, scale, version and deploy.
The more you can provoke thought within your own mind, the more prepared you will be in tackling the complex problem of slaying your monolithic PHP app.
9. Build an asynchronous aggregator
Generally speaking, PHP is blocking — there are ways around it (pthread, forking, stream_set_blocking) but for the most part you'll want to procure an asynchronous aggregation service.
The purpose of this service is to receive one call from the PHP app, and return the result of a variety of calculations and HTTP calls on its behalf. That is, delegate your expensive calls and calculations to this service.
NodeJS is my favourite tool for this job, as it's super-fast, quick to build and most importantly can make asynchronous HTTP/Rest calls.
10. Push static assets to a CDN
Find, minify, compress, obfuscate, version and push all of your static assets to a CDN. Pull them out of your app and repo, and into its own.
Commit to an asset management process and toolchain. This should be relatively simple to do, and helps reduce the size of your app deployments and repos. Check out gruntJS and composer.
Change the rules to suit
While these are my tried and tested rules, you'll need to form your own 90-day strategy because every company, tech stack and team is different. Take these 10 rules and most importantly make them your own. The key is to find that first win, and the rest will fall into place.