Below you will find pages that utilize the taxonomy term “Design”
Good design means it's easy-to-change
Software development seems to be about change: the business changes and we need to reflect those changes, so the requirements or specifications change, frameworks and libraries change, so we have to change our integrations with them, etc. Changing the code base accordingly is often quite painful, because we made it resistant to change in many ways.
Code that resists change
I find that not every developer notices the “pain level” of a change. As an example, I consider it very painful if I can’t rename a class, or change its namespace. One reason could be that some classes aren’t auto-loaded with Composer, but are still manually loaded with require
statements. Another reason could be that the framework expects the class to have a certain name, be in a certain namespace, and so on. This may be something you personally don’t consider painful, since you can avert the pain by simply not considering to rename or move classes.
What's a simple solution?
“As I’m becoming a more experienced programmer, I tend to prefer simple solutions.” Or something similar. As is the case with many programming-related quotes, this is somewhat of a blanket statement because who doesn’t prefer simple solutions? To make it a powerful statement again, you’d have to explain what a simple solution is, and how you distinguish it from not-so-simple solutions. So the million-dollar question is “What is a simple solution?”, and I’ll answer it now.
Violating the Dependency rule
I write about design rules a lot, but I sometimes forget to:
- Mention that these rules can’t always be applied,
- Describe when that would be the case, and
- Add examples of situations where the rule really doesn’t matter.
The rules should work in most cases, but sometimes need to be “violated”. Which is too strong a word anyway. When someone points out to me that I violated a rule, I’m like: Wow! I violated the rule? I’m so sorry! Let’s fix this immediately. Whereas in practice it should be more like: Yeah, I know that rule, but it makes more sense to follow that other rule here, because […]. In other words, pointing out that a certain rule has been violated should not be a sufficient reason to adhere to that rule. My favorite example is “But that violates SRP!” (Single Responsibility Principle). Whoops, I wouldn’t want to do that! Or would I?
Relying on the database to validate your data
One of my pet peeves is using the database schema to validate data.
Several ways in which this normally happens:
- Specifying a column as “required”, e.g.
email VARCHAR(255) NOT NULL
- Adding an index to force column values to be unique (e.g.
CREATE UNIQUE INDEX email_idx ON users(email)
) - Adding an index for foreign key integrity, including cascading deletes, etc.
Yes, I want data integrity too. No, I don’t want to rely on the database for that.
Test-driving repository classes - Part 2: Storing and retrieving entities
In part 1 of this short series (it’s going to end with this article) we covered how you can test-drive the queries in a repository class. Returning query results is only part of the job of a repository though. The other part is to store objects (entities), retrieve them using something like a save()
and a getById()
method, and possibly delete them. Some people will implement these two jobs in one repository class, some like to use two or even many repositories for this. When you have a separate write and read model (CQRS), the read model repositories will have the querying functionality (e.g. find me all the active products), the write model repositories will have the store/retrieve/delete functionality.
Test-driving repository classes - Part 1: Queries
There’s something I’ve only been doing since a year or so, and I’ve come to like it a lot. My previous testing experiences were mostly at the level of unit tests or functional/system tests. What was left out of the equation was integration tests. The perfect example of which is a test that proves that your custom repository class works well with the type of database that you use for the project, and possibly the ORM or database abstraction library you use to talk with that database. A test for a repository can’t be a unit test; that wouldn’t make sense. You’d leave a lot of assumptions untested. So, no mocking is allowed.
Final classes by default, why?
I recently wrote about when to add an interface to a class. After explaining good reasons for adding an interface, I claim that if none of those reasons apply in your situation, you should just use a class and declare it “final”.
PHP 5 introduces the final keyword, which prevents child classes from overriding a method by prefixing the definition with final. If the class itself is being defined final then it cannot be extended.
More code comments
Recently I read a comment on Twitter by Nikola Poša:
I guess the discussion on my thread is going in the wrong direction because I left out a crucial hashtag: #NoCommentsInCode - avoid comments in code, write descriptive classes, methods, variables.https://t.co/MuHoOFXCvV
— Nikola Poša (@nikolaposa) July 13, 2018
He was providing us with a useful suggestion, one that I myself have been following ever since reading “Clean Code” by Robert Martin. The paraphrased suggestion in that book, as well as in the tweet, is to consider a comment to be a naming issue in disguise, and to solve that issue, instead of keeping the comment. By the way, the book has some very nice examples of how comments should and should not be used.
Layers, ports & adapters - Part 3, Ports & Adapters
In the previous article we discussed a sensible layer system, consisting of three layers:
- Domain
- Application
- Infrastructure
Infrastructure
The infrastructure layer, containing everything that connects the application’s use cases to “the world outside” (like users, hardware, other applications), can become quite large. As I already remarked, a lot of our software consists of infrastructure code, since that’s the realm of things complicated and prone to break. Infrastructure code connects our precious clean code to:
Layers, ports & adapters - Part 2, Layers
The first key concept of what I think is a very simple, at the very least “clean” architecture, is the concept of a layer. A layer itself is actually nothing, if you think about it. It’s simply determined by how it’s used. Let’s stay a bit philosophical, before we dive into some concrete architectural advice.
Qualities of layers
A layer in software serves the following (more or less abstract) purposes:
Layers, ports & adapters - Part 1, Foreword
Looking back at my old blog posts, I think it’s good to write down a more balanced view on application architecture than the one that speaks from some of the older posts from 2013 and 2014. Before I do, I allow myself a quick self-centered trip down memory lane.
Why Symfony? Seven facts
The archive tells an interesting story about how my thoughts about software development changed over time. It all started with my first post in October 2011, How to make your service use tags. Back in those days, version 2 of the Symfony framework was still quite young. I had been working with symfony (version 1, small caps) for a couple of years and all of a sudden I was using Symfony2, and I absolutely loved this new shiny framework. I learned as much as I could about it (just as I had done with version 1), and eventually I became a Certified Symfony Developer, at the first round of exams held in Paris, during a Symfony Live conference. During those years I blogged and spoke a lot about Symfony, contributed to the documentation, and produced several open source bundles. I also wrote a book about it: A Year With Symfony.