Recently, I’ve been writing a PHP app for an upcoming Twilio tutorial. The premise of the app is pretty simple, and started out as a joke between my siblings and I; but that’s a story for another day.
It lets a user subscribe to be notified by their local council when their rubbish bins will next be collected. That way, they don’t have to maintain a diary or look out the window every few days to see if their overly punctual neighbours have put their bins out, to know that they need to as well.
In fairly typical style for my Twilio tutorials, I:
- Started out with the application’s central design premise;
- Mapped out the idea on my office whiteboard; and
- Built the application in a fairly freewheeling kind of way, when I had it all clear in my head
It took about a week, part-time, to build the application. When it was done, I was pretty proud of it. I felt that I’d architected it well enough for what I needed, and that I’d also done a good job of naming all of the classes and variables as well as the directory structure, making it reasonably intuitive.
Then, I discovered a problem
As I sat reviewing it all, it became apparent that it was going to be quite a challenge to cover it in an engaging way in a tutorial, because there was just so much to cover.
For example, there was code for handling routes, for making requests to OpenStreetMap, Twilio, and SendGrid’s APIs, for interacting with the SQLite database (using Doctrine), and for filtering and validating user input. This was in addition to the code required to instantiate all of the required classes, such as the Twilio Client and SendGrid objects, so that the app could interact with those APIs.
While I didn’t write any of the code just for the sake of doing so, there was still too much, such that, in my opinion, it was distracting from the core focus of the tutorial.
Now this might seem like a strange thing to say. Perhaps you’re thinking that if the code needs to be there, it needs to be there. In answer to that, I’d say “yes and no”, or as I’m quite fond of saying, “it depends”.
Production code and tutorial code are two very different beasts
In tutorials, the main aim is to teach a few key points, such as how to interact with a given API. The code doesn’t need to be highly performant, doesn’t need to be maintainable (though ideally you’d try to encourage that), and it doesn’t need to be efficient.
What’s more, often times, even instantiating the various objects that you’ll use isn’t important either. What is important is communicating how the code works, how to use the various classes and methods, and teaching the reader about what can go wrong. And, if your code interacts with APIs for example, you’d also cover the request options and response bodies, along with their HTTP codes.
That way, the user gets a complete picture of what they’re working with. Then, they can go off and explore further and experiment with whatever it was that you were teaching them.
Given that, to cover all of the code that I’d written so far would have taken a master job in planning, writing, and editing – in order not to lose the reader along the way or bore them to death.
To add some proverbial flesh to the bone of just how much code there was to cover, there was more 30 classes, 3 traits, 9 template files, and 5 configuration files!
Sure, only a few of the classes were more than 10 - 15 lines long. And most of them only contained 1, perhaps 2, functions at most. But, as you’ll appreciate, that’s still a lot to write about, not to mention for the reader to take in – and keep in their head through to the conclusion of the tutorial.
I needed to find a way to pare back the code
That way the tutorial only covered the essential information and concepts – nothing else! Given that, I started conducting a series of intense code reviews looking for where the code could be reduced, simplified, or eliminated.
I looked for absolutely anything and everything that I could remove, so that the tutorial could focus as close to the central concepts as possible. For starters, I was able to remove a lot of boilerplate code, combined classes, and extracted code out into reusable utility methods.
Then, after reviewing the handlers, I saw that they didn’t need dedicated factories for instantiation, as I was used to. The factories were only retrieving services from the DI container to instantiate the handlers. Given that, I deleted the factories and updated the DI (Dependency Injection) Container’s configuration to use the Reflection-based Abstract Factory instead.
This was a massive step forward! But, eventually, I came to a point where I felt that I couldn’t go any further. Yet, I still felt that there was too much to cover. How could I reduce it further?
Then, I thought:
Why not extract code out into libraries?
After all, it’s standard practice to only write what you need and then lean on third-party packages most other tasks. So why not create more of my own in this case too? What’s more, it’d be good practice to create some more open source packages, and in the process, potentially, help others with the same or similar needs.
What was extracted into external packages?
Specifically, I saw that the instantiation and configuration logic for the core SendGrid, Twilio, and OpenStreetMap classes could be avoided. For these, I created three packages: laminas-sendgrid-integration, laminas-twilio-integration, and laminas-openstreetmap.
The packages each did three things:
- Provided factories to instantiate the respective objects
- Provided default configuration files which the factories would read from, files that the user could copy to config/autoload
- Registered services for the respective objects with the DI container thanks to the package’s ConfigProvider class.
After installing them, the user only needed to copy the default configuration files from each package to config/autoload, know which environment variables to set, and how to set them. laminas-openstreetmap didn’t even require that!
With the packages created, I now felt that I’d gone far enough in stripping anything out of the applications that could be avoided, so that as sharp a focus on teaching the core concepts was happening.
That’s why I encourage you to build your own software packages
There’s quite a bit more to this story, but I won’t go on, as it’s unlikely that you’ll have the same motivations as I do, regularly, these days. It’s more likely that you just want to make whatever software you’re working on easier to reuse, whether by yourself or others.
Regardless of what your motivation is, I believe that building your own software packages is a good thing, both for yourself and for others. You can share what you know, demonstrate your skills and competency as a developer, and contribute something that others can use.
What software packages and libraries have you created and why? Let me know in the comments. I’d love to know!