Should we use a framework?
Since I’ve been writing a lot about decoupled application development it made sense that one of my readers asked the following question: “Why should we use a framework?” The quick answer is: because you need it. A summary of the reasons:
- It would be too much work to replace all the work that the framework does for you with code written by yourself. Software development is too costly for this.
- Framework maintainers have fixed many issues before you even encountered them. They have done everything to make the code secure, and when a new security issue pops up, they fix it so you can just pull the latest version of the framework.
- By not using a framework you will be decoupled from Symfony, Laravel, etc. but you will be coupled to Your Own Framework, which is a bigger problem since you’re the maintainer and it’s likely that you won’t actually maintain it (in my experience, this is what often happens to projects that use their own home-grown framework).
So, yes, you/we need a framework. At the same time you may want to write framework-decoupled code whenever possible.
Dynamically changing the log level in Symfony apps
This is just a quick post sharing something I was able to figure out after doing some research.
The situation: our application throws exceptions by means of “talking back to the user”. As developer we don’t want to be notified about all these exceptions. They aren’t as important as any other exception that should be considered “critical”. Still, we do want to find these exceptions in the logs, because they can sometimes provide valuable feedback about the usability of the system.
A simple recipe for framework decoupling
If you want to write applications that are maintainable in the long run, you have to decouple from your framework, ORM, HTTP client, etc. because your application will outlive all of them.
Three simple rules
To accomplish framework decoupling you only have to follow these simple rules:
- All services should get all their dependencies and configuration values injected as constructor arguments. When a dependency uses IO, you have to introduce an abstraction for it.
- Other types of objects shouldn’t have service responsibilities.
- Contextual information should always be passed as method arguments.
Explanations
Rule 1
Following rule 1 ensures that you’ll never fetch a service ad hoc, e.g. by using Container::get(UserRepository::class)
.
This is needed for framework decoupling because the global static facility that returns the service for you is by definition framework-specific.
The same is true for fetching configuration values (e.g. Config::get('email.default_sender')
).
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.
Free book chapter: Key design patterns
I wanted to share with you a free chapter from my latest book, “Advanced Web Application Architecture”. I’ve picked Chapter 11, which gives a compact overview of all the design patterns that are useful for structuring your web application in a way that will (almost) automatically make it independent of surrounding infrastructure, including the web framework you use.
Chapter 11 is the first chapter of Part II of the book. In Part I we’ve been discovering these design patterns by refactoring different areas of a simple web application. Part II provides some higher-level concepts that can help you structure your application. Besides design patterns, it covers architectural layering, and hexagonal architecture (ports & adapters). It also includes a chapter on testing decoupled applications.
Release of the Advanced Web Application Architecture book
100% done
I’m happy to announce that my latest book “Advanced Web Application Architecture” is now complete. With ~390 pages it has become a well-rounded book full of useful design patterns and architectural principles built around the notion of object-pure code, that will help you create decoupled applications that are testable by definition, and support a domain-first approach to software development.
Use this link to get 10% off the price: https://leanpub.com/web-application-architecture/c/RELEASE_DAY
Unit test naming conventions
Recently I received a question; if I could explain these four lines:
/**
* @test
*/
public function it_works_with_a_standard_use_case_for_command_objects(): void
The author of the email had some great points.
-
For each, my test I should write +3 new line of code instead write,
public function
testItWorksWithAStandardUseCaseForCommandObjects():
void
-
PSR-12 say that “Method names MUST be declared in camelCase”. [The source of this is actually PSR-1].
-
In PHPUnit documentation author say “The tests are public methods that are named test*” and left example below
Book release: PHP for the Web
While Advanced Web Application Architecture is still a work in progress, I decided to release another project in the meantime: a book for beginning PHP developers called PHP for the Web.
Of course, there are PHP books for beginners, but most of them aren’t very concise. They cover many related topics like relational databases, CLI applications, and sending emails. I wanted to write a book that only shows what makes PHP so special when it comes to web development.
DDD and your database
The introduction of Domain-Driven Design (DDD) to a larger audience has led to a few really damaging ideas among developers, like this one (maybe it’s more a sentiment than an idea):
Data is bad, behavior is good. The domain model is great, the database awful.
(We’re not even discussing CRUD in this article, which apparently is the worst of the worst.)
By now many of us feel ashamed of using an ORM alongside a “DDD domain model”, putting some mapping configuration in it, doing things inside your entities (or do you call them aggregates?) just to make them easily serializable to the database.