A collection of more than 250 articles about Software Design & Development Best Practices.
With code samples for PHP/Symfony and Fortran applications.
Successful refactoring projects - Set the right goal
Refactoring is often mentioned in the context of working with legacy code. Maybe you like to define legacy code as code without tests, or code you don’t understand, or even as code you didn’t write. Very often, legacy code is code you just don’t like, whether you wrote it, or someone else did. Since the code was written the team has introduced new and better ways of doing things. Unfortunately, half of the code base still uses the old and deprecated way…
Successful refactoring projects - Prepare to stop at any time
Refactoring projects
A common case of refactoring-gone-wrong is when refactoring becomes a large project in a branch that can never be merged because the refactoring project is never completed. The refactoring project is considered a separate project, and soon starts to feel like “The Big Rewrite That Always Fails” from programming literature.
The work happens in a branch because people actually fear the change. They want to see it before they believe it, and review every single part of it before it can be merged. This process may take months. Meanwhile, other developers keep making changes to the main branch, so merging the refactoring branch is going to be a very tedious, if not dangerous thing to do. A task that, on its own, can cause the failure of the refactoring project itself.
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 functiontestItWorksWithAStandardUseCaseForCommandObjects():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
