The post Advice for junior developers appeared first on Entropy Wins.
]]>Structure:
This blog post mentions and links valuable concepts that you can explore further as you see fit.
As developers, we like writing code. Most of us want to be given a nice unambiguous task. A fun technical puzzle to solve without paying attention to the rest of the world.
Put reasonable effort into making sure that you are solving the right problem. To quote Peter Drucker: There is nothing so useless as doing efficiently that which should not be done at all. Gather feedback early and often, typically by continuous delivery to real users. Be Agile.
Software development is expensive, with the vast majority of the effort of real-world projects typically going into maintenance. Combine this with the goal being user/business outcomes, the best code is often no code. To quote Bill Gates: “Measuring programming progress by lines of code is like measuring aircraft building progress by weight.”
See also: YAGNI, KISS, The Last Responsible Moment.
During the first 5 years of my development career, I thought that software design is for software architects or other people with special roles. I was focused on “getting things done”, and saw software design and practices such as writing tests, as a distraction at best. My code worked, and I was getting a lot of things done. Or so I thought.
Then I read Clean Code, by Robert C. Martin. This book motivates caring about software design and contains examples and many technical heuristics. The central takeaway of the book is: “The only way to go fast is to go well“. In other words, if you make a mess, it will slow you down. See also: TradableQualityHypothesis, DesignStaminaHypothesis
Learning how to write well-designed clean code of course takes time and effort. And when you start, you will be slower and make mistakes. Simple is not Easy.
Writing tests tends to be beneficial. There are exceptions, but most of the time, it makes a lot of sense to write automated tests. Writing tests is an example of a best practice.
If you are new to writing tests, just follow the best practice and write tests for everything. When starting, blindly following the best practice will be better than following your own underdeveloped judgment. Over time you will learn how to write tests effectively, and be able to tell the difference between you have messed up, and situations where writing a test is not worth it. You will also start to understand the value tests bring on a more visceral level, by having experienced the decrease in debugging sessions and the worry-free refactoring enabled by your tests. After developing your judgment, you will be able to transcend the best practice.
This advice applies to best practices in any area that you are a junior in. Automated tests are just an example.
One big gotcha is that it is not easy to tell the difference between a sensible best practice and something nonsensical or even counterproductive. This is made more complicated by most existing code being a mess, and by most developers, including “experienced” and “senior” ones, not knowing software design basics. This makes having a good mentor extremely valuable. Barring that, one piece of advice based on my own experiences is to be wary of best practices specific to the community of your language or framework. Look for evergreen advice that has been around for decades.
Our focus will be on technical topics. Many other areas are essential, such as health, happiness, career, and soft skills. Knowing how to avoid a technical pitfall won’t help you if you are sleep deprived and working on the wrong problem for a toxic boss that underpays you.
Write automated tests. Perhaps write tests before the code, such as via Test Driven Development (TDD). This makes it easy to verify your code is correct in a repeatable manner, thus saving you from much manual retresting and from debugging sessions.
You think test-first is difficult? Try debug-after.
Perhaps even more importantly, tests give you the safety net to refactor your code. And continuous refactoring is needed to keep your code clean. Without a reliable test suite, it is all the more likely that your code will rot.
Writing tests is difficult if the design of your code is poor, such as when using inheritance for code reuse, or when using static functions. If on the other hand, you have SOLID classes, with no global dependencies, then writing nice tests is not so difficult.
Test design matters because poorly written tests will slow you down. Avoid binding your tests to implementation details of the code under test or to the structure of the system. Avoid overusing Mocks and write better Test Doubles.
This is one of those best practices that bring to mind the “Use the Best Practices” section. My advice: do not use inheritance for code reuse at all when you are starting out. It is rarely the right call and can do a lot of harm. Favor composition over inheritance.
Write SOLID code that is not STUPID. There is so much value in understanding these principles and anti-patterns.
Actually create objects. Classes with only static methods are not OO. Try to avoid using static code altogether.
See also: my defense of SOLID.
(Functional programming is not to be confused with imperative structural programming.)
This point is not about entriely switching to a functional language. You can benefit from using a functional style in your OO language. Minimize state, especially mutable state, and do one thing in your functions. See also: functional core, imperative shell.
Copy-pasting big chunks of code to multiple places is almost always unwise. Any self-respecting developer soon learns this and starts to follow some form of Don’t Repeat Yourself (DRY). Unfortunately, the well-intended pursuit of DRY often leads to overengineering and accidental complexity. This is where the counterpart of DRY comes in: Write Everything Twice (WET). The idea behind WET is to only deduplicate on the third occurrence of duplication.
For a more in-depth look at the costs and benefits of deduplication, see The Fallacy of DRY.
Try to write self-documenting code and avoid comments.
Every time you write a comment, you should grimace and feel the failure of your ability of expression. — Robert C. Martin
Comments are dangerous because they can lie. The code can change without the comment being updated. New code can be added right under the comment. The comment might have been wrong or inaccurate in the first place. When this happens, the comment not only becomes useless, it becomes misleading.
To write self-documenting code:
Clean Code by Robert C. Martin has some good rules of thumb about naming and comments.
See also: Recommended Reading for Developers by Jeff Atwood
The post Advice for junior developers appeared first on Entropy Wins.
]]>The post Using PSR-3 Monolog in MediaWiki appeared first on Entropy Wins.
]]>If you have used Monolog before, you presumably know how to create a logger and add handlers to it. Most people configure MediaWiki logging using $wgDebugLogGroups. This config however does not allow us to inject our (Monolog) Logger instance into MediaWiki.
Instead, you can use $wgMWLoggerDefaultSpi, which specifies a service that creates the loggers MediaWiki uses. You could use the MonologSpi that MediaWiki provides. But as you can see on the MonologSpi documentation, the standard MediaWiki approach here might not align with your expectations. There is no way to inject your Logger instance created via the standard Monolog approach.
We can get around this by creating our own mini Spi implementation. In this implementation, you can either create (and cache) the Logger or take an existing Logger instance. The below copy-pastable example shows how to configure MediaWiki to use an existing Logger instance.
$logger = new \Monolog\Logger('name'); $logger->pushHandler( new \Monolog\Handler\StreamHandler( __DIR__ . '/cache/error.log', \Monolog\Logger::ERROR ) ); $wgMWLoggerDefaultSpi = [ 'factory' => function() use ( $logger ): \MediaWiki\Logger\Spi { return new class ( $logger ) implements \MediaWiki\Logger\Spi { private \Monolog\Logger $logger; public function __construct( \Monolog\Logger $logger ) { $this->logger = $logger; } public function getLogger( $channel ) { return $this->logger->withName( $channel ); } }; } ];
Since you construct the Logger yourself, you can configure it as you like, with all the tools available in the Monolog ecosystem.
The above example uses PHP 7.4.
The post Using PSR-3 Monolog in MediaWiki appeared first on Entropy Wins.
]]>The post Value Objects with PHP 8.1 appeared first on Entropy Wins.
]]>Back in the dark ages of 2016, shortly after PHP 7.0 was released, I wrote a Missing In PHP 7 blog post series. Four of the five posts describe functionality that is no longer missing, as of PHP 8.1 or earlier. Missing in PHP7: Value objects is one of those posts.
You can find a quick recap on what a Value Object is, and why you would want to use them, in Missing in PHP7: Value objects.
class ContactRequest { public function __construct( public readonly string $firstName = 'nyan', public readonly string $lastName = 'cat', public readonly string $emailAddress = 'something', ) { } } $request = new ContactRequest(firstName: 'foo', lastName: 'bar', emailAddress: 'baz'); $firstName = $request->firstName; $request->lastName = 'hax'; // Fails
Other new PHP features that I am excited about:
The post Value Objects with PHP 8.1 appeared first on Entropy Wins.
]]>The post New MediaWiki blog appeared first on Entropy Wins.
]]>Half a year ago I launched Professional Wiki together with Karsten Hoffmeyer. Professional Wiki is, as the name suggests, a company providing professional wiki services. We help companies create and manage wikis, we provide training and support and we offer fully managed wiki hosting.
Today we published our new blog featuring a first post on installing MediaWiki extensions with Composer. This blog will contain both wiki news and longer lived articles, such as the one about Composer.
In recent years I was hesitant to post MediaWiki specific content on this blog (EntropyWins) because it had evolved a focus on software design. The new Professional Wiki blog solves this problem, so you can expect more MediaWiki related posts from me again.
The post New MediaWiki blog appeared first on Entropy Wins.
]]>The post Applications as Frameworks appeared first on Entropy Wins.
]]>In your typical web application, the code handles a request and returns a response. Let’s assume we are using a web framework to handle common tasks such as routing. Let’s also assume that we think framework binding has a high cost, and are thus decoupling our application from the framework. The flow of control would look like this:
Execution starts with the framework. For PHP frameworks this will be in a file like public/index.php
. The framework then bootstraps itself and does a bunch of stuff. It’s safe to assume this stuff will include routing, and often it also includes things like dependency construction and error handling.
After the framework did the tasks you want it to do, it hands control over to your application. Your application does a bunch of application and domain logic and interacts with persistence. It likely uses a number of libraries, especially for infrastructure tasks like logging and database access. Even so, control stays with the application. (The key difference between frameworks and libraries is that you control/call libraries while frameworks control/call you.) Your application might also be calling the framework and use it as a library. Again, control stays with the application.
Finally when the application is done, it hands some kinda of result back to the framework. The framework then does another bunch of stuff, like template rendering and translations. In case of a web framework it then spits out a HTTP response and execution ends.
An application like this keeps you in control of what happens, making it easier to change things. This style also makes it easy to decouple from the framework. There are only two points where you need to decouple.
My post Implementing The Clean Architecture outlines one architectural approach that leads to this kind of application.
Let’s compare how frameworks and applications differ when they are used as a foundation for an/another application.
Frameworks don’t do stuff on their own. There is no application or domain logic. There is no set of existing web pages or API endpoints with their own structure and behavior. This is all defined by your application when using a framework. When building on top of an application that acts as a framework, you’ll need to deal with existing structure and behavior. You’ll need to insert your own stuff, change existing behavior in certain situations and prevent default behavior altogether in others.
I know that there are “frameworks” that do provide their own stuff out of the box. (Example: web shop framework.) While they might not be a full application on their own, for the purpose of this blog post they are the same as an application that gets used as a framework.
There is nothing inherently bad about building things on top of an application. Plugins and extensions are a very useful pattern. A plugin that interacts with a single plugin point can decouple itself when appropriate, and it is in control over itself. For smaller plugins that use many plugins points, framework decoupling might not be feasible or worth the effort.
This post is about using applications as framework foundation for sizable sets of code which are applications in their own right.
Let’s imagine we have an application that is used on some site for some use case. We’ll call this application FrameworkApp, since we’ll use it as framework for another application that powers another site.
When building our application on top of FrameworkApp, we’ll need to register new behavior and modify existing behavior. To make this possible, FrameworkApp needs to provide the appropriate extension points. Often these take the form of abstract classes or even systems, though the exact nature of the extension points is not important for our purposes.
This leads to a very different flow of control. Rather than calling us once, the FrameworkApp calls each extension point our application handles.
The diagram is showing just 6 extension points, though there can be 100s.
When visualized like this, it becomes easy to see how decoupling from the framework becomes almost impossible. Even if you manage to avoid coupling to framework code in your application, its whole structure is still defined by the framework. This means you are very limited in what you can do in your application and need to understand the framework to effectively develop the application. Framework coupling causes more issues than that, though a comprehensive overview of those is out of scope for this post.
Favor composition over inheritance
— OOP principle
Using an application as a framework is very similar to using inheritance for code reuse.
Just like with the application that is build on top of the app that acts as framework, the subclass might not be in control and be invoked many times from the base class. This is especially the case when using the Template Method Pattern and when having a deep inheritance hierarchy. The flow of control can bounce all over the place and decoupling the subclass from the classes up the hierarchy becomes all but impossible.
You can avoid this classical inheritance mess by using composition. Which suggests one way to move away from using an application as a framework or avoid doing so altogether: stop treating the framework as a base class. If there is code to share, use composition. This way you stay in control, can decouple easier and avoid The Fallacy of DRY.
Just like with class hierarchies you can always slap on an extra level.
The post Applications as Frameworks appeared first on Entropy Wins.
]]>The post Readable Functions: Guard Clause appeared first on Entropy Wins.
]]>function doThing() { var $thing = 'default'; if (someCondition()) { $thing = 'special case'; } return $thing; }
Using a Guard Clause we can simplify it to:
function doThing() { if (someCondition()) { return 'special case'; } return 'default'; }
The if statement in this simplified code is a Guard Clause. You can have multiple Guard Clauses in a function.
The simplification removes ALL the state in the function, including the nasty and completely not needed mutation in the first form of the code. You can read the new code sequentially, and the code after the Guard Clause is not polluted by extra complexity arising from the special case.
This post is part of the Readable Functions series which contains tricks like this one and two general principles: Minimize State and Do One Thing.
The post Readable Functions: Guard Clause appeared first on Entropy Wins.
]]>The post My year in books appeared first on Entropy Wins.
]]>I read 21 fiction books and 13 non-fiction ones. The fiction books were all either hard science fiction or pleb science fiction while the non-fiction ones were mostly about psychology or finance.
The price for 2018 best fiction book that I read goes to Children of Time by Adrian Tchaikovsky. This book had me so gripped that I spent 5h per day reading it till it was finished.
Children of Time is a wonderful hard Science Fiction novel. It deals with the rise and fall of civilizations and takes a delightful evolutionary angle in the story. The story has a lot in common with A Deepness in The Sky by Vernor Vinge, one of my all-time favorite books.
It also reminded me of Pandora’s Star by Peter F Hamilton, in particular how the Primes civilization (in Pandora’s Star) rises from the unthinking depths to something waging interstellar war. Beyond that these two novels are very different in tone and focus.
I was going to pick The Righteous Mind by Jonathan Haidt though then realized I beat myself to it by including it in my 2017 book summary.
With The Righteous Mind being disqualified, first place goes to 12 Rules for Life: An Antidote to Chaos by Jordan Peterson.
This book contains a lot of useful information on personal growth, meaning, ethics and applied psychology. Though who am I kidding, the reason it gets first place is because rule 12 is “Pet a cat when you encounter one on the street”.
Second place goes to Homo Deus: A Brief History of Tomorrow. This book is about the human condition, the challenges we have faced as a species and, most important of all, what the outline of those challenges that are up ahead could look like.
While I really liked both 12 Rules and Homo Deus, I was not a fan of the final chapters(s) of either book. Since I read Thinking Fast and Slow I recognized the tendency for Duration Neglect via Peak-end Averaging. Knowing how your own mind tends to go off the rails is so useful.
13 of the 21 novels I read are part of the same series, so it deserves a mention: The Polity by Neal Asher. It has more than a few similarities with The Culture universe by Iain M Banks.
The novel Prador Moon tells the story of how the Culture comes into contact with the war-like Idirans. Caught off balance, the ship minds quickly ramp up military production while fighting a retreating and delaying action. Wait… I meant Polity, Prador, and ship AIs. Not sure how I got those mixed up.
That said the Polity novels lack certain bits of awesome common to the Culture novels, such as the definitely superior Culture ship names and antics. On the flip side, the Prador are much more built out than any alien race in the Culture novels, and so is the Jain threat.
I particularly enjoyed the later (more recent) novels in the series. Recommended for people that like stories of increasing scale in a well built out universe.
Much of what I read is in the form of blog posts and articles. And then there are also many educational videos I watch. Here are some resources that I spend a lot of time-consuming or came across in 2018 that piqued my interest.
In 2018 I, for the first time, read over 1000 pages per month. Such achievement!
The post My year in books appeared first on Entropy Wins.
]]>The post Readable Functions: Do One Thing appeared first on Entropy Wins.
]]>Often functions become less readable because they are doing multiple things. If your function Foo needs to do tasks A, B and C, then create a function for each of the tasks and call those from Foo.
Having small functions is OK. Having just 3 calls to other functions in your function is OK. Don’t be afraid of “too simple” code or of this style making things harder to follow (it does not (unless you are splitting things up stupidly)). And don’t be afraid of performance. In most programs the amount of function calls have effectively 0 impact on performance. There are exceptions, though unless you know you are dealing with one of these, don’t mash things together for performance reasons.
Doing one thing includes dealing with a single level of abstraction. For instance, suppose you have a function in which in some cases a message needs to be logged to the file system.
function doThing() { if (condition) { low_level_write_api_call('write-mode', $this->somePath, 'Some error message'); } }
Here the details of how the error message is logged are on a lower level of abstraction than the rest of the function. This makes it harder to tell what the function is actually doing, because details that don’t matter on the higher level of abstraction clutter the high level logic. These details should be in their own function.
function doThing() { if (condition) { $this->log('Some error message'); } } private function log(string $message) { low_level_write_api_call('write-mode', $this->somePath, $message); }
The post Readable Functions: Do One Thing appeared first on Entropy Wins.
]]>The post PHP Typed Properties appeared first on Entropy Wins.
]]>As of version 7.3, PHP supports types for function parameters and for function return values. Over the latest years many additions to PHP types where made, such as primitive (scalar) types like string
and int
(PHP 7.0), return types (PHP 7.0), nullable types (PHP 7.1) and parameter type widening (PHP 7.2). The introduction of typed properties (PHP 7.4) is thus a natural progression.
Typed properties work as follows:
class User { public int $id; public string $name; public function __construct(int $id, string $name) { $this->id = $id; $this->name = $name; } }
You can do in two simple lines what takes a lot more boilerplate in PHP 7.3 or earlier. In these versions, if you want to have type safety, you need a getter and setter for each property.
 private $id; private $name; public function getId(): int { return $this->id; } public function setId(int $id): void { $this->id = $id; } public function getName(): string { return $this->name; } public function setName(string $name): void { $this->id = $name; }
Not only is it a lot more work to write all of these getters and setters, it is also easy to make mistakes when not automatically generating the code with some tool.
These advantages are what the hype is all about. People are saying it will save us from writing so much code. I think not, and I am afraid of the type of code those people will write using typed properties.
Let’s look at some of different types of classes we have in a typical well designed OO codebase.
Services are classes that allow doing something. Loggers are services, Repositories are services and LolcatPrinters are services. Services often need collaborators, which get injected via their constructor and stored in private fields. These collaborators are not visible from the outside. While services might have additional state, they normally do not have getters or setters. Typed properties thus do not save us from writing code when creating services and the added type safety they provide is negligible.
Entities (DDD term) encapsulate both data and behavior. Normally their constructors take a bunch of values, typically in the form of Value Objects. The methods on entities provide ways to manipulate these values via actions that make sense in the domain language. There might be some getters, though setters are rare. Having getters and setters for most of the values in your entities is an anti-pattern. Again typed properties do not save us from writing code in most cases.
Value Objects (DDD term) are immutable. This means you can have getters but not setters. Once again typed properties are of no real help. What would be really helpful however is a first-class Value Object construct part of the PHP language.
Typed properties are only useful when you have public mutable state with no encapsulation. (And in some cases where you assign to private fields after doing complicated things.) If you design your code well, you will have very little code that matches all of these criteria.
By throwing immutability and encapsulation out of the window, you can often condense code using typed properties. This standard Value Object …
class Name { private $firstName; private $lastName; public function __construct(string $firstName, string $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } public function getFirstName(): string { return $this->firstName; } public function getLastName(): string { return $this->lastName; } }
… becomes the much shorter
class Name { public string $firstName; public string $lastName; public function __construct(string $firstName, string $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } }
The same goes for Services and Entities: by giving up on encapsulation and immutability, you gain the ability to not write a few lines of simple code.
This trade-off might actually make sense if you are working on a small codebase on your own or with few people. It can also make sense if you create a throw away prototype that you then actually throw away. For codebases that are not small and are worked on by several people writing a few simple getters is a low price to pay for the advantages that encapsulation and immutability provide.
Typed properties marginally help with type safety and in some rare cases can help reduce boilerplate code. In most cases typed properties do not reduce the amount of code needed unless you throw the valuable properties of immutability and encapsulation out of the window. Due to the hype I expect many junior programmers to do exactly that.
The post PHP Typed Properties appeared first on Entropy Wins.
]]>The post Readable Functions: Minimize State appeared first on Entropy Wins.
]]>What makes functional programming so powerful? Why do developers that have mastered it say it makes them so much more productive? What amazing features or capabilities does the functional paradigm provide to enable this enhanced productivity? The answer is not what you might expect if you never looked into functional programming. The power of the functional paradigm does not come from new functionality, it comes from restricting something we are all familiar with: mutable state. By minimizing or altogether avoiding mutable state, functional programs skip a great source of complexity, thus becoming easier to understand and work with.
If you are doing Object Orientated Programming you are hopefully aware of the drawbacks of having mutable objects. Similar drawbacks apply to mutable state within function scope, even if those functions are part of a procedural program. Consider the below PHP code snippet:
function getThing() { var $thing = 'default'; if (someCondition()) { $thing = 'special case'; } return $thing; }
This function is needlessly complex because of mutable state. The variable $thing
is in scope in the entire function and it gets modified. Thus to understand the function you need to keep track of the value that was assigned and how that value might get modified/overridden. This mental overhead can easily be avoided by using what is called a Guard Clause:
function getThing() { if (someCondition()) { return 'special case'; } return 'default'; }
This code snippet is easier to understand because there is no state. The less state, the less things you need to remember while simulating the function in your head. Even though the logic in these code snippets is trivial, you can already notice how the Accidental Complexity created by the mutable state makes understanding the code take more time and effort. It pays to write your functions in a functional manner even if you are not doing functional programming.
While mutable state is particularly harmful, non-mutable state also comes with a cost. What is the return value of this function?
function getThing() { $foo = 1; $bar = 2; $baz = 3; $meh = $foo + $baz * 2; $baz = square($meh); print($baz); return $bar; }
It is a lot easier to tell what the return value is when refactored as follows:
function getThing() { $foo = 1; $baz = 3; $meh = $foo + $baz * 2; $baz = square($meh); print($baz); $bar = 2; return $bar; }
To understand the return value you need to know where the last assignment to $bar
happened. In the first snippet you, for no reason at all, need to scan up all the way to the first lines of the function. You can avoid this by minimizing the scope of $bar
. This is especially important if, like in PHP, you cannot declare function scope values as constants. In the first snippet you likely spotted that $bar = 2
before you went through the irrelevant details that follow. If instead the code had been const bar = 2
like you can do in JavaScript, you would not have needed to make that effort.
With this understanding we arrive at two guidelines for scope in functions that you can’t avoid altogether in the first place. Thou shalt:
Indeed, these are two very general directives that you can apply in many other areas of software design. Keep in mind that these are just guidelines that serve as a starting point. Sometimes a little state or mutability can help readability.
To minimize scope, create it as close as possible to where it is needed. The worst thing you can do is declare all state at the start of a function, as this maximizes scope. Yes, I’m looking at you JavaScript developers and university professors. If you find yourself in a team or community that follows the practice of declaring all variables at the start of a function, I recommend not going along with this custom because its harmful nature outweighs “consistency” and “tradition” benefits.
To minimize mutability, stop every time you are about to override a variable and ask yourself if you cannot simplify the code. The answer is nearly always that you can via tricks such as Guard Clauses, many of which I will share in follow up posts. I myself rarely end up mutating variables, less than once per thousand 1000 lines of code. Because each removal of harmful mutability makes your code easier to work with you reap the benefits incrementally and can start applying this style right away. If you are lucky enough to work with a language that has constants in function scopes, use them as default instead of variables.
Thanks to Gabriel Birke for proofreading and making some suggestions.
The post Readable Functions: Minimize State appeared first on Entropy Wins.
]]>