Coming from the JEE world, I was used to adding several layers of abstraction for high level enterprise projects. Even back then, I was trying to evaluate the necessity of some of the layers.
PHP is an interesting language, currently the most popular scripting (or maybe any programming) language at all for web projects. Developed naturally for non-developers without OOP nature (added in the next versions), loading everything on every single request, it lacks the concept of a number of complex layers with enterprise design patterns. Most projects follow flat-hierarchy, simple and straight forward structure (PHP doesn’t support multithreading as well) which leads to a simple code (easier to read), hardly maintainable and incredible to scale and extend when the project gets old and expands enough.
There is a small number of developers who come from the higher language world (like Java or .NET) used to all design patterns for facades, decorators, bridges, abstract factories, DAO/DTO and so on, implementing them in PHP projects. It’s usually cool and leads to a better control over the projects once you spend enough time browsing across the different ‘incoming’ external parameters taking action within the calls.
I’m usually ‘for’ that, as most of the projects lack any kind of maintainability. However:
Don’t overuse abstraction
Abstraction, as one of the OOP paradigms, is the quality of a product to include the exact type and number of properties for a given object, structure or module so that it covers everything that takes place in a project and ignores the unnecessary details. It’s an art of a prophet to foresee in the future and cover everything and omit the details, but it’s worth following it.
But, please, don’t overuse abstraction. During the past 2 years I’ve seen the following samples:
- 2 extra routers in a project evaluating a complex logic for a path creation that is being used in a single line of code. If you happen to reach that snippet, you might end changing 30 lines of complex conditional code instead of defining a single path variable and calling it in place
- Extra front-end controllers for 2 static modules. We’re all set that no modules are to be added in a given direction, but we implement 2 controllers for handling paths there and calling them blindly from the outside.
- Context-driven parameter passing. This might get handy, instead you overabstract the context paradigm. JEE has the CDI pattern implemented in Struts and other frameworks, but it is plain to understand compared to the static string that is passed in a dynamic typeless language passed or not, string or array, boolean or null, or whatever. Since the language lacks threads, it’s hard to ‘inject’ there the context that you actually need.
- One method to handle it all. It’s when you delegate 3 actions to 1 function and end up with 20 lines of conditional codebase instead of adding three functions 3 LoC each in the same class.
- Delegate to JavaScript. Handy for AJAX, but still, when you create JavaScript representation of the backend (all classes ported to JS), created in the PHP, parsed as objects, then passed as JSON to PHP, then json_decoded, parsed again, managed, fetched, changed, returned as JSON, JSON-decoded in the frontend, parsed and outputted. That usually happens in a non-AJAX environment at the end.
- Using third-party scripts and extra pre-compilers with no real use. CoffeeScript and Cass/Less are a popular trend right now, and they should be used in some of the projects – for the better OOP handling of CS and variables/mixins/CSS3 control in CSS pre-languages. However, if you use them just to be fancy and write their name in the project description (without benefiting from their features) you end up with extra code-writing, compiling and tough debugging due to the code not being written by you.
- Improperly designing an abstraction layer for something that requires a flexible modification control later. If you abstract 10 different functions in a class/method that generates everything upfront, and you need a modification, you’ll add an extra bulk to the functions that don’t need that modification. When it happens for 3 or 4 times in a row, the majority of functions should pass through a number of loops and conditionals that are not directly addressed to them.
With that in mind, I’m still ‘hands up’ for the abstraction theory and that it shall be bundled in all projects. But carefully. Apply only where necessary. Don’t restrict the flexibility, don’t increase the codebase when no needed, don’t provide an extension layer when you’re a 100% sure that it won’t get any updates ever again. Reuse external and proven APIs (social networks, maps, etc) and rely closely on their API as much as possible. Don’t override framework cores, don’t use them at all if you are about to get a fraction of their functionality. Think three times, slice once.