Enterprise Laravel Help Me: White-Labeled Clothing Stores
This is a series of posts on Enterprise Laravel.
!Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.
Recently, I grew tired of hearing people say, "Laravel is fine for small apps, but when you are working in the Enterprise..." You can almost hear the capital E in enterprise, like they're talking about the starship.
I've spent the last few months trying to gather information about what makes people say this, and also stories of folks who are already successfully working with Laravel in enterprise context. I put out a survey to collect stories, and wrote and delivered a talk (which I hope to give again soon) titled "Laravel and the Enterprise."
As a part of my goal of helping dispel this myth that Laravel is bad for enterprise work, I wanted to hear not just from success stories, but also from people who were having trouble. I put up a "Help me!" form and promised that, whenever I can find time, I'll respond to those messages and help folks with any challenges they're running into.
Some of these questions can be very practical, and I can respond with some code or a package, or even by working with the submitter to make a pull request to Laravel core or the Laravel docs.
But some of these questions are architectural, and for those I can almost never make a great recommendation without knowing more than I can learn from a "Help me!" form submission.
So, instead, I just give the best advice I can based on the information I have in front of me. Remember—this is advice to this person based on the information I know about them, and if this advice doesn't work for your project, then it's not for you.
Case Number One
Here's our first submission: an anonymous Laravel-based project that allows their tenants to establish their own white-labeled storefronts selling a few specific pieces of clothing. We have scale, taking money, regulation and reporting, dev/ops complexity, pain-if-site-goes-down, and quite a few more of my "characteristics of enterprise projects", so while you might not think of all e-commerce as "enterprise", I think there's at least enough here for it to be interesting.
Without further ado, let's go!
Note: I've modified the original request to try to remove any identifying information, and also fixed any typos.
FROM: [Redacted] TO: Matt Stauffer SUBJECT: Help Me!
This project was all about creating endpoints initially, and then we added in checkout/ecommerce, queues for creating orders, sending emails etc. We extracted an internal package as the codebase for checkout as a separate laravel app.
There are a few problems:
Despite caching, we find that we have to up our servers when we are about to launch a new tenant as otherwise our app cannot handle all the traffic. I am not sure on how to optimise the app. We have already done the basic stuff (caching, indexing, etc.)
The code is getting a bit messy and it's harder to keep track of what's happening—not sure if we need diagrams, etc. but if we do, how do we maintain them, where/how do we create them in the first place?
Sometimes because of rushing I have ended up adding code just to get the job done instead of thinking about it.
Initially it was a simple CRUD-ish but evolved to be more of a monolith... and we were thinking of moving to microservices but that has their own cons.. too much faffe around between API Gateway and microservices API... and versioning which means another layer of complexity.
Maybe DDD would be better? But we tried that using a module and it also doesnt feel right—e.g. too many extra folders (for events/listeners etc. being created which we might not use)
END OF MESSAGE
Have you taken a look at what’s slowing down?
If it's the database, you may find that certain behaviors (writes vs. reads, commerce vs. basic page content) should be split out to another database. Or maybe you move the entire thing to a service like RDS. You can also be more selective about your caching, possibly putting most of your reads into an in-memory cache so only write operations have to directly hit the database. You may even want to look into full-page cache, serving just static HTML to the majority of your visitors on the majority of your pages.
If it’s the application server (memory or processor), do you have any complex processes you can identify that are either optimizable or moveable to a queue or a microservice?
If it’s access to an external service, consider throwing a cache or a microservice in front of it.
2. Messy code
You may want to start with a simple Markdown document sharing what your conventions are for what goes where. This could also have a sort of mind map in outline form of the bigger pieces of code (e.g. models vs. controllers vs. service classes) and any meaningful organization or conventions or groups within each big section.
If you want to go bigger than that, you may want to generate database and UX diagrams. If so, use whatever tool is simplest (the Omni tools are great but pricy) and then store it in whatever your preferred documentation tool is. I’ve seen folks use GitHub, wikis, Basecamp, and more.
Sometimes messy code doesn’t need more documentation but instead refactored code. The more your code is comprised of small, simple classes and methods and functions, the less likely it is to be hard to follow—especially with someone whose IDE lets them click on a method or class and navigate straight to its definition.
3. Adding code to get the job done
Spiking is fine. The question is, do you ever come back and refactor it later?
We all have to write code quickly some times. But if you can’t convince whoever determines your schedule that it’s worth refactoring and testing and cleaning up that spiked code, you’re just asking for the whole thing to melt down in six months. Learn how to convince your boss now that addressing technical debt early and frequently is core to the business’ success.
4. Considering microservices
Don’t go for microservices as a massive refactor. Rather, understand what they provide and what they don’t; and when you’re in a situation that might merit a microservice, ask yourself the question, are the benefits to be gained here worth the potential costs?
For example: You have an external API that you’re calling and their API is awkward and slow. Sometimes you can address this with a clean API client you write in PHP and some caching. But some times it’s not just that—It’s also that the timing of their data availability and their rate limits will make it impossible for you to get the data when you need it, even with a clean API client and caching. Then? Microservice time. But don’t jump straight to microservices. You’re right; there are a lot of costs that come along with them. Don’t reach for them just because they’re “better”.
Here’s what you should learn from DDD: Use language in your code that mimics the language your business/product people use. If you have a relationship on a model, for example, and the model it’s related to is the “User”, but in your business’s brain that relationship is to the “Trainer”, then name it trainer.
None of the tooling folks have proposed in the DDD space, and few of the conventions, are worth your time. The concepts are often (but not always) good but those tools don’t make DDD. And neither do those conventions.
Convention-wise, my advice is to always stick with the Laravel conventions unless they cause you pain. Then find the best tool to meet the pain you are feeling at that moment.
I hoped this helped you out! Are you looking for advice like this on your enterprise Laravel application? Get in touch!
Comments? I'm @stauffermatt on Twitter
This is part of a series of posts on Enterprise Laravel: