There is a segment of the programming world that thinks they understand Object-Oriented Programming. It is, after all, just functions and data inside of a wrapper right? Well, technically, yes, but that gives an impression and development practice that is wrong. It ignores what OOP tries to solve.
Problem 1: Procedural Programming Limitations
Well, I should clarify that procedural development is not a problem in and of itself. Most simple programs under 100K lines of code or one off programs would probably be better served using procedures (also known as functions in most languages). Well, the general guideline that I’ve read in books and online is <100K lines of code, but I will say that a barrier of maintainability is capped around 10K to 20K lines of code. There are very few developers and projects that I’ve seen where the flow of the project and usage of functions is clear after that range.
The problem with procedural programming is that care has to be taken to logically group the functions and their control flow. To often the APIs I’ve seen hand you many functions and then toss you into the mine field as to how to navigate them. Sure, documentation does a long way, but where is the starting point? However, once you have that, the functions should just work off of that as to what you are trying to accomplish.
The best way is to create a module that is contained and works off a specific set of data to manipulate it. However, given this is akin to how object-oriented development works, it makes more sense to use objects. But, often at the fault of the developer and not the paradigm, the program or project is a mess.
The reason for creating modules is reuse and extensibility. You shouldn’t have to rewrite the same functionality for each project. That doesn’t make any sense, and yes it is possible with procedural programming, but after a while the scope of the functionality becomes far more difficult to separate mentally. What I’m trying to say, is that the API grows so large that refactoring it becomes either impossible given the time and the dependencies that would have to be broken out or understanding of the original problem that the solution was developed for is not possible.
The purpose of an API is for others to understand and grasp it in order to use it to their best ability. When you lack documentation, cohesiveness, and where the true starting point is, then well, hopefully there is another better written API that does what you want or you know enough to write your own implementation. I’ve been there with C/C++ procedural APIs. Well, okay, part of it was my lack of understanding of programming, at the time, and lack of understanding of C/C++.
Problem 2: Reuse and Extensibility
Well, the goal of development is to create a solution that can be reused and extended as much as possible. If a solution is not extensible, then its reuse is limited and it will have to be rewritten or a new solution written that solves a similar, specific problem. What is sad, is that is easiest with procedural programming as you just need to create a new function (when the API is well written) that accepts the main starting point parameters and manipulates or handles the data.
Developing an object that allows extensibility is simple in that you can extend the parent class and add methods and rewrite the parent’s methods. The problem with this, is in languages that only allow you to call a specific object name. So even through you’ve extended the object, you still need to go through the code and change the references to the parent object’s name. One solution for this, is to use the Factory or Adapter Pattern. If you’ve tried the Factory Pattern, then it isn’t really a solution at all for this problem.
Problem with the Factory Pattern is that it is known beforehand what the object name is or you can replace it with your own. You then have another layer on top of your API in order to allow for this type of overriding of the class. This becomes stupid as you have to create layer upon layer just to allow for the caller to correctly get the right class that does what they want when they replace one of yours. Where does that shit stop? Well, it stops when you get bored and start to wonder why the Factory Pattern is useful.
I have to admit that I kind of like the idea behind the Adapter and Plugin Patterns. What I like about it, is that you can extend the base class without having to inherit it and create a whole new object. It doesn’t require a Factory, because the name never has to change. You can also extend it and create new base functionality for a whole new program based off the new object.
The goal should be never to have to recreate functionality that exists within another object. That is perhaps the difficulty with working with objects, is that each object dependencies will be different. This also has to be within the scope of the application.
If you are accessing a file, the API is going to be basic enough to never have to rewrite that functionality (although that is not to mention the at least 3 ways to do such a thing within PHP, not to mention the 3 or 4 ways to traverse a directory). Granted people are going to have their own “way” of implementing similar functionality and some is going to be better than others. That said, I developed a wrapper for the various HTTP implementations in PHP and the wrapper is standardized enough to either be used with the “main” class or alone, so that if you don’t like the main class, you can just ignore it and write your own implementation using the self-contained HTTP transport classes. It isn’t “perfect” in that it still requires code from the main class that would have to be implemented in the new class.
Problem 3: Elegance in its Simplicity
Creating a class library that is both reusable and extensible is extremely difficult and most implementations make it overly obtuse to replace functionality. Doing so, should be clear to the developer that they are just implementing or replacing one component and not dealing with dependencies. The replacement or component should be its only dependency. Forcing them to extend a class or work through dependencies just to implement something simple is not the best or ideal solution. Granted at least an interface will be required, but that should be it and that should allow the developer to use existing classes they’ve built.
Code Igniter forces you to either extend the base class for which it will use your class within its own or to replace it completely. That is a neat trick to say the least, but it is still a WTF? The Code Igniter code base is completely oriented on the Blob anti-pattern with methods that defy completely the C.R.A.P index. Not to mention limitations that should not exist. The work-flow is so ugly, it is great that it “just works,” because going through the code base to fix bugs, well I wouldn’t want to go through that hell.
Well, the advantage to Code Igniter, is that it is extremely easy framework to understand and work off of. The one framework that is more to my liking, Yii Framework, takes a bit more time to understand, but it is also that I haven’t yet developed a project with it. What I like about it, is that it has a great deal more and better features than Code Igniter and the license is better (clearer, better understanding of rights) with the Yii Framework.
The goal should always to create something that is easy to use, but allows for more advanced usage. This usually means creating a wrapper or a layer on top of the API that complements it, to make easing into the API faster, because it is easier to understand. I believe the Swift Mailer and HTML Purifier APIs did a great job in this aspect of object-oriented development. You didn’t have to know about the more arcane parts of the API, you just needed to know what you needed to work with. If you had to, then you could dive deeper into the code and figure it out.
Rehashing the Solution
Quite simply, coding is about making development easy. You, the developer, do the bulk of the hard work, so that the person using your code doesn’t have to. It is often that you’ll use your own code and it is better to not have to recode it. It saves time reusing code and not having to rewrite existing code to work within the constraints of the class library or framework you are working with.
Possibly Related Posts: