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.

7 thoughts on “Over-abstractionism”

  1. Matthew says: October 18, 2012 at 3:50 pm

    Abstraction is certainly a thing to be done in moderation. I by no means am experienced enough to pull a workplace example, but I can from my own endeavors.

    When I looked into the DDD standard, one important concept I grasped was what to abstract and what not to. The line of abstraction was clear as the naming conventions themselves. For example – I like to consider Services like an API to your persistence layer.

    When you’re calling from your controller, you’re interacting with an entirely new layer to obtain information. The Controller should have no care in what the workings of the Model layer are. With this kind of ambiguity, I am free to shape my Model layer better. So whenever I encounter a need to authenticate a user, I call the userAuthenticationService. That Service will then call upon the Repository to do the work it needs with DAOs and VOs, Upon completion, the Repo will return back to the Service as a return value that allows for the next instruction.

    So in that respect, there is a clear reason to abstract: we keep the persistence layer segregated so switching to a Cloud Storage solution or some other I/O will be done easily. Then one more abstraction is done in the Model layer where Repositories can be changed up to offer different internal workings, while still satisfying the return values expected by the calling Service.

  2. admin says: October 18, 2012 at 4:01 pm

    Hey Matthew,

    Thanks for your input. An additional ‘open to discussion’ point could be the TDD approach, writing the tests before any codebase so that taking the reverse approach you would need to implement the architecture based on your end expectations. This is an interesting approach that could help you define the specific level of abstraction and the number of arguments/properties required for the end product to work properly.

  3. Matthew says: October 18, 2012 at 4:24 pm

    Yes! I was reading about TDD last week. I agree on that as well. You could counter that TDD can be inflexible if your client’s requirements change drastically. Then again, I haven’t encountered that problem much. At least not to the degree where a massive code-rewrite in the foundation was needed. Most of the time it’s just your usual CRUD.

    Just found your blog today, I plan to keep reading. 🙂

  4. Kate says: November 6, 2012 at 3:14 pm

    Thanks for sharing the great news! It was included into a digest of the hottest and the most interesting PHP news: http://www.zfort.com/blog/php-digest-november-5-2012-zfort-group/

  5. admin says: November 6, 2012 at 3:27 pm

    Thank you, I saw the Russian version last week as well, glad to be of any help.

Leave a Reply

Your email address will not be published. Required fields are marked *