Archive for the 'Blablabla' category

Legacy code is 3rd party code

published on July 19, 2018.

Within the TDD community there’s an advice saying that we shouldn’t mock types we don’t own. I believe it is good advice and do my best to follow it. Of course, there are people who say that we shouldn’t mock in the first place. Whichever TDD camp you’re in I think this “don’t mock what you don’t own” advice has an even better advice hidden in it. An advice that people often overlook because they see the word “mock” in it and go full berserk.

This hidden advice is that we should create interfaces, clients, bridges, adapters between our application and the 3rd party code we use. Will we create mocks from those interfaces in our tests doesn’t even matter that much. What matters is that we create and use these interfaces so that our application is better decoupled from the 3rd party code. A classic example of this in the PHP world would be to create and use an HTTP client within the application that uses the Guzzle HTTP client, instead of using the Guzzle client directly in the application code.

Why? Well, for one, Guzzle has a much bigger public API than what your application (in most cases) needs. Creating a custom HTTP client that exposes only the required subset of Guzzle’s API will limit what the application developers can do with it. If Guzzle’s API changes in the future, we’ll have to change how we call it in only one place, instead of trying to make the required changes in the entire application and hope that we broke nothing. Two very good reasons and I haven’t even mentioned mocks! gasp

I don’t think this is that hard to achieve. 3rd party code lives in a separate folder from our application code, usually in vendor/ or library/. It also has a different namespace and naming convention than our application code. It is fairly easy to spot 3rd party code and with a bit of a discipline we can make our application code less dependant on 3rd parties.

What if we apply the same rule to legacy code?

What if we start looking at our legacy code the same way we look at the 3rd party code? This might be difficult to do, or even counterproductive, if the legacy code is in a maintenance-only mode, where we only fix bugs and tweak bits and pieces of it. But if we are writing new code that is (re)using legacy code, I believe we should look at legacy code the same way we look at 3rd party code, at least from the perspective of the new code.

If at all possible legacy and new code should live in different folders and use different namespaces. It’s been a long time since I last saw a system without autoloading so this is doable. But instead of just blindly using legacy code within the new code, what if we create interfaces for the legacy code and use those in the new code?

Legacy code is all too often full of “god” objects that do way too many things. They reach out to global state, have public properties or magic methods that expose privates as if they were public, have static methods that are just so convenient to call from anywhere and everywhere. Well, guess what? That convenience got us in this situation in the first place.

Another, maybe an even bigger issue with legacy code is that we are so ready to change it, fix it, hack it, because we don’t see it as a 3rd party code. What do we do when we see a bug or when we want to add a new feature to 3rd party code? We open up an issue and/or create a pull request. What we don’t do is go inside the vendor/ folder and make our changes there. Why would we do that to legacy code? And then we cross our fingers and hope we didn’t break anything.

Instead of blindly using legacy code within new code, let’s try writing interfaces that will expose only the required subset of the legacy “god” object’s API. Say we have a User object in the legacy code that knows everything about everyone. It knows how to change emails and passwords, how to promote forum members to moderators, how to update a user’s public profile, set notification settings, how to save itself, and so much more.

src/Legacy/User.php

<?php
namespace Legacy;
class User
{
    public $email;
    public $password;
    public $role;
    public $name;

    public function promote($newRole)
    {
        $this->role = $newRole;
    }

    public function save()
    {
        db_layer::save($this);
    }
}

It’s a crude example, but shows the problems: every property is public and can be easily changed to whatever value, we have to remember to explicitly call the save method after any change for these changes to persist, etc.

Let’s limit and prohibit ourselves from reaching out to those public properties and having to guess how does the legacy system work any time we want to promote a user:

src/LegacyBridge/Promoter.php

<?php
namespace LegacyBridge;
interface Promoter
{
    public function promoteTo(Role $role);
}

src/LegacyBridge/LegacyUserPromoter.php

<?php
namespace LegacyBridge;
class LegacyUserPromoter implements Promoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function promoteTo(Role $newRole)
    {
        $newRole = (string) $newRole;
        // I guess you thought $role in legacy is a string? Guess again!
        $legacyRoles = [
            Role::MODERATOR => 1,
            Role::MEMBER => 2,
        ];
        $newLegacyRole = $legacyRoles[$newRole];
        $this->legacyUser->promote($newLegacyRole);
        $this->legacyUser->save();
    }
}

Now when we want to promote a User from the new code we use this LegacyBridge\Promoter interface that deals with all the details of promoting a user within the legacy system.

Change the language of the legacy

An interface for the legacy code gives us an opportunity to improve the design of the system. An interface can free us from any potential naming mistakes we did in the legacy. The process of changing a user’s role from a moderator to a member is not a “promotion”, but rather a “demotion”. Nothing stops us from creating two interfaces for these two different things, even though the legacy code sees it the same:

src/LegacyBridge/Promoter.php

<?php
namespace LegacyBridge;
interface Promoter
{
    public function promoteTo(Role $role);
}

src/LegacyBridge/LegacyUserPromoter.php

<?php
namespace LegacyBridge;
class LegacyUserPromoter implements Promoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function promoteTo(Role $newRole)
    {
        if ($newRole->isMember()) {
            throw new \Exception("Can't promote to a member.");
        }
        $legacyMemberRole = 2;
        $this->legacyUser->promote($legacyMemberRole);
        $this->legacyUser->save();
    }
}

src/LegacyBridge/Demoter.php

<?php
namespace LegacyBridge;
interface Demoter
{
    public function demoteTo(Role $role);
}

src/LegacyBridge/LegacyUserDemoter.php

<?php
namespace LegacyBridge;
class LegacyUserDemoter implements Demoter
{
    private $legacyUser;
    public function __construct(Legacy\User $user)
    {
        $this->legacyUser = $user;
    }

    public function demoteTo(Role $newRole)
    {
        if ($newRole->isModerator()) {
            throw new \Exception("Can't demote to a moderator.");
        }
        $legacyModeratorRole = 1;
        $this->legacyUser->promote($legacyModeratorRole);
        $this->legacyUser->save();
    }
}

Not that big of a change, yet the intent of the code is much clearer.

Now the next time you want to reach out to that legacy code and call some methods on it, try and make an interface for it. It might not be feasible, it might be too expensive to do. I know that static method on that god object is really easy to use and will get the job done much quicker, but at least consider this option. You might just improve the design of the new system you’re building a tiny little bit.

Happy hackin’!

Easier Mocking With Mockery in php[architect]

published on April 20, 2018.

In early February I got an email from Oscar would I be willing to write an article for php[architect], based on my “Easier mocking with Mockery” talk. It took me maybe 2 seconds to think about it and say “Yes!”. The first part of the article was published in the April’s edition of the magazine. Lots of useful content in there, not just my article!

Initially I was supposed to write a 3000 word article on the subject, but in the end I wrote somewhere around 8000 words. Oops. Oscar was kind enough to let me keep the entire thing, so it was split into a two part article. I really enjoyed writing it and working with the fine folks from php[arch] on was great. I hope I get to write more for them.

If you have an idea for a PHP related article, I wholeheartedly recommend reaching out to them. It is really a great feeling to be a published author, even if it’s “just” 3000 words.

Happy hackin’!

Tags: php, mockery, article.
Categories: Blablabla.

Bounded contexts and subdomains

published on March 20, 2018.

Back in October last year I wrote that I thought I understood bounded contexts, what they are and why we need them. Ever since realizing that a bounded context is a boundary of how a business sees a specific subject within a section of that business, learning anything and everything DDD became a lot easier.

I see bounded contexts as a big building block without which learning other parts of DDD is pretty much pointless. OK, pointless might be too harsh a word, but to be able to use entities, value objects, domain events, aggregates to their full potential, a good understanding of bounded contexts is needed.

Of course I didn’t stop learning about DDD since writing that post 5 months ago. If anything, I did my best to learn even more by reading books and articles, watching recorded conference talks, and thinking about this subject. A lot.

Uh, phrasing

In my previous post I had this image attached that I used to help explain the difference between a Book in two different bounded contexts. Recently I realized that that image has mistake in it. On that image I used the terms “Publisher” and “Seller” to distinguish the two bounded contexts. A better name for those would probably be “Publishing” and “Selling”.

It is important to get the naming right as it affects the understanding a great deal. It might not be an outright mistake, but a bounded context is probably better off not being named after a thing. Publisher, seller, warehouse, these are the things we model inside our bounded contexts. A bounded context should name in what context do these models apply: publishing, selling, warehousing. Properly naming a bounded context will also help to identify should a model of something be an aggregate (root), an entity, or a value object.

There are probably other things I got wrong in that post, but so far I see this naming issue as the biggest one.

What about subdomains?

One thing I didn’t know and understand when I was writing the previous post was the importance of (sub)domains in connection with bounded contexts. I’m still not 100% sure I do. A business operates within a domain and that’s what we’re trying to design and model with DDD. It has one core domain which represents the reason why the business exists in the first place and at least one more subdomain that supports that core domain. The core domain is the main problem a business is trying to solve and the subdomains are all the other problems that come along with trying to solve the core domain problem.

Vaughn Vernon in his “Implementing Domain-Driven Design” book states (I’m paraphrasing here a bit) that “the subdomains live in the problem space and the bounded contexts in the solution space”. It took me a while to really understand this and what the implications of it are.

When writing software that will support the business and help solving the problems coming from the core domain and supporting subdomains we create models. These models will be “fine tuned” so that they provide the most optimal solution for the problem. But to provide these solutions, we also need to say what is the context of these models in which they help solve the problem.

Imagine a software that is being developed to support a dentist. A dentist has two problems: fixing patients’ teeth and making appointments for the patients. Fixing teeth is the core domain and making appointments is a supporting subdomain. In the core domain the medical staff cares about a patient’s dental history, can they handle general anesthesia or not, what their current problem is, etc. In the subdomain the staff (not necessarily medical staff) cares about a patient’s contact information, a date and a time that best suits both the doctor and the patient, the type of dental work needed, etc. Both domains need a model of a patient, but that model will depend on the bounded context we put in place to ensure the correct information and features are available when solving the problems of each domain.

Subdomains and bounded contexts go hand in hand and I think one can’t be understood without the other. The optimal solution would be to have one bounded context in one subdomain. The world is not a perfect place, software even less so, so it might happen that one bounded context spans multiple subdomains, or that one subdomain has multiple bounded contexts.

Problems and solutions

A key element to DDD is that our understanding of the domain will constantly change, improve, as we learn more about it. That’s one of the reasons why we need to be ready to change or throw away models we came up with. This ever-evolving state means that the subdomains and the bounded contexts can and will change, too.

A bounded context can grow or shrink, split in two, be combined in one, regardless of the subdomain(s) it is in. Taking a different approach in solving a problem doesn’t mean that the problem itself has changed.

On the other hand if the problem changes, the solution should change too. If during development we realize that the core domain can be further split into a smaller, more focused core domain and a new subdomain then the solution to those problems should change. Most likely the models we developed don’t fit the problems any more and the boundaries around our contexts have moved.

This post has evolved, too

Initially this wasn’t the post I wanted to write. I did start writing about bounded contexts, but then I realized I can’t talk about them without talking about subdomains. Both the title and the contents changed at least 3 times. More topics to cover in the future I guess.

Happy hackin’!

A weekly to-do

published on March 08, 2018.

About a year ago I listened to a ThatPodcast episode where Dave and Beau talked about bullet journalling. I found the idea of it appealing, but over the next few months I just couldn’t find a bullet journal in any of the (book)stores I went to. As time passed so did my interest in this. After all, I was getting along without such a system just fine. My life isn’t that crazy busy, 7-8 hours of sleep, 7-10 hours of work work, and the rest is up for grabs — hanging out with my wife Senka (her name translates to Shadow, how cool is that?), reading, writing, cooking, open source, whatever.

For work work I’m organized, a Google calendar, couple of Trello boards, and that’s pretty much it. No issues there. My free time though… I realized that can get a bit messy from time to time. Especially when Senka works 2nd shift, then it’s just me and our cat from 5pm until 10pm that entire week. Lots of time there and I soon noticed that when I want to do lots of things all at once, nothing gets really done.

In September or October last year I read somewhere, can’t remember was it a book or an article, something about organizing to-do tasks in weekly chunks. Now that was an interesting idea especially since Senka changes shifts weekly which means that with a weekly plan/schedule I could plan things around her shifts. Quality time with her comes first. Then I remembered the bullet journalling thing and started thinking about a way to combine these two in one system.

For the past 4 months I’ve been using this weekly to-do approach where every Monday morning I write down what I need and want to do during the week. Going to the bank to pay the bills, sending out an email to a friend to catch up, writing a blog post, having a DnD session, look into a open source issue, organize an upcoming trip, finish reading a book I was putting off for way too long. If something pops up during the week I add it to the list. If something gets “obsolete”, cross it off. Every item gets a dot in front of it, just like with bullet journaling. Once it’s done I turn that dot into a plus and write down the date.

Next Monday I tally the previous week by writing down the to-do vs. done ratio. For any items left over from the previous week I turn the dot into a greater than sign and move it over to the new week and add new items to the list. If a task list “overflows” for 3 weeks in a row I strike it through and move it a Trello board full of stuff that probably won’t ever happen. I mean if I couldn’t find the time to do something in 3 weeks I guess it’s just not that important after all.

4 months of this and it’s working really great for me. There are weeks when I end up having almost 20 items on the list and there are weeks when I have 5 or 6. Weeks when I finish everything are rare, happened maybe 3 times so far. I’m fine with that as the things that really need to be done or I really want them done get done. The rest takes care of itself.

The past 3 weeks I’ve been experimenting with adding a weekly focus note which should act as a guiding system if the items on the list are too scattered, so just to keep myself in check that I’m actually working on the things that will worth the most over time. Another improvement I’m thinking about is somehow to measure and note the biggest accomplishment of the previous week so that maybe I could also see some general progress over the months.

Happy hackin’!

Tags: about, to-do, bullet journal.
Categories: Blablabla.

My OBS setup for recording screencasts

published on February 21, 2018.

Last year I started recording my contributions to open source. I wasn’t really regular, so today I published only the 9th episode: OSS Contribution 9.

Anyway, now I’m at the point where I am happy with the overall quality of the recording, both with the video and the audio and I want to write down the current setup so that I can recreate it in the future if I need to.

I’m using a Sennheiser GSP 300 headset and the microphone that comes with it. A really great product, I love it.

PulseAudio is responsible for the audio in my Fedora system. In the “Input Devices” settings of PulseAudio, I have set the “loudness” of the microphone to 25% or -35.94dB. I got there after a lot of trial and error.

As for the recording software, I was first using Zoom, which is a video conferencing and screen sharing tool. Start a meeting with myself, share screen, record. Buuut… I was never really happy with the audio.

I tried out Open Broadcaster Software, or OBS, last week. Again, after a lot of trial and error, I think I have the perfect settings given the hardware that I’m using. I picked it up from Swizec, he’s using it for his live coding sessions I believe.

“Settings > Output”: Output mode: simple, video bitrate: 2500, encode: software (x264), audio bitrate: 160, recording quality: indistinguishable quality, recording format: mp4. “Settings > Audio”: Sample rate: 44.1khz, the rest is all default. “Settings > Video”: Base resolution: 1920x1080, output resolution 1920x1080, the rest is default.

The most improvement came from setting filters on the microphone — “Mic/Aux > gear icon > Filters”. The first filter I added is “Noise Suppression” with a value of -17. The second filter is “Noise Gate” with a “Close Threshold” of -44, “Open Threshold” of -42, “Attack Time” 25ms, “Hold Time” 200ms, and “Release Time” 150ms. These last three might be the defaults, I’m not sure. I did play around with them.

Now, I said I’m happy with the audio, but I know it can be much better. One, I need to speak louder, and two, if these screencast become a more regular thing then I’ll invest in a better microphone. Until then, this will do.

Happy hackin’!

Tags: obs, screencasts, recording, about.
Categories: Software, Blablabla.
Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2018
Get the feed