AuthorFélix Dion-Robidoux

Reverting “Coming Soon” page from CPanel Website Builder

This is an issue I got recently that might make some people scratch their heads.

I was browsing the stuff from my Namecheap hosting’s CPanel interface, and accidentally used the “Website Builder” option on my main domain (www.fdrobidoux.com).

This created a Coming Soon page on the index.

I didn’t ask for this. So I fixed it.

The Solution :

  • Go into the folder on your server where your WordPress installation resides.
  • Delete the index.php file.
  • Rename the spb_index.php file to index.php.
  • Done!

Needless to say, I won’t be using that feature again in the future!

What happened to this blog?

My name is Félix Dion-Robidoux. I lost access to this domain name back in 2022, while I was under the process of moving to the USA. I have ADHD, and so I didn’t see time go by as I let my professional domain expire. Fortunately, I have it back!

And now, I need help getting it’s reputation back. If you see this and you are an authority on DNS servers and/or phishing, you can be sure this website is in good hands once again, and I will not sell your data. (pinky promise!)

As such, once this is all resolved, I will bring back this website up, good as new.

Thank you for your support!

Félix Dion-Robidoux

PSA: Stop using Streams and Reader/Writers to Convert Strings/ByteArrays

Stop doing this :

using (var memory = new MemoryStream())
{
    using (StreamWriter writer = new StreamWriter(memory, Encoding.ASCII))
    {
        foreach (var lineData in dataLines)
        {
            writer.WriteLine(lineData);
        }
        
        writer.Flush();
        return memory.GetBuffer();
    }
}

Just… do this instead.

return Encoding.ASCII.GetBytes(lineData.Join("\n\r"));

Trust me, it’s not worth using streams unless you explicitly need to.

Using “Emojis” when naming Pull-Requests

Today, I started my new job at JStratégia as a mobile developer. For the first 4 hours, I worked on setting up my brand new Lenovo Thinkpad, (never had one, they’re sweeeeet !) getting my emails set up on both mobile and on the laptop, meeting the team…

And then I was explained for the remaining 2 hours how the neighboring team worked for the past 6 months, and it was a mindblowing experience.

One of the biggest revelations I had out of the many great practices they had within their git workflow, was to use emojis at the beginning of the title of the pull request. This might sound odd at first, but here’s some examples :

If it’s a feature, name it, for example :
? Mobile : Responsiveness to sales view

If it’s a bugfix, use this :
? Apache : Access to root from a regex pasted in url

For adding tests :
☑ Setup : Compat. Linux, Mac OS, Windows and Solaris

In case you’re upgrading a library the project depends on, or adding new ones :
? NPM : leftpad 2.0.2 to 2.1.4

When it involves the documentation :
? Deployment : Extra troubleshooting

This has multiple advantages :

1. It’s fun

Well, duh. Emojis are fun. ?

2. It’s easier to give a meaningful, but descriptive title.

You can waste a lot of time trying to conjugate your sentences in a coherent manner, but here you’ll keep it short and sweet.

3. It’ll give quick-scan skills to reviewers

You won’t feel guilty of writing “Fixed deployment bugs” and fear that any extra details will be glossed over if you add anything more, but reducing on details won’t help either. Plus, there is now a clear distinction between category, sub-category and description.

4. You can count ’em !

When you’ll be making a post-mortem, you’ll be able to easily count emojis by making a search for them and counting the results for every time they come up. This means you can count how many times bugs, features, documentation and testing were worked on, and compare with past projects to get a feel of what’s been prioritized the most.

So, what do you folks do at work to improve your git workflow ? I’d love to know !

Asynchronous calls and assignments using Tuples to reduce if…else hell

Don’t you hate having a huge amount of if...else for multiple async operations in a single function? Those are the kind of code smells we’re gonna look at here in this article.

Take a look at the example below. It is heavily inspired from real production code in a basic ASP.NET controller method for a form that has an external REST API to fetch dynamic dropdown values.

Task<HttpResponseData<DropdownValue>> obtainCategoriesTask = _restApiClient.obtainDropdownValues("categories");
Task<HttpResponseData<DropdownValue>> obtainTagsTask = _restApiClient.obtainDropdownValues("tags");
Task<HttpResponseData<DropdownValue>> obtainAuthorsTask = _restApiClient.obtainDropdownValues("authors");

var categoriesList = await obtainCategoriesTask;
if (categoriesList.Success)
{
    var tagsList = await obtainTagsTask;
    if (tagsList.Success)
    {
        var authorsList = await obtainAuthorsTask;
        if (authorsList.Success)
        {
            // Do stuff with the data
        }
        else
        {
            throw new Exception("One of the API calls has resulted in an error.", callGroup.Item1.Exception);
        }
    }
    else
    {
        throw new Exception("One of the API calls has resulted in an error.", callGroup.Item1.Exception);
    }
}
else
{
    throw new Exception("One of the API calls has resulted in an error.", callGroup.Item1.Exception);
}

So, what’s wrong with this code ?

1. It’s not DRY.

DRY means “Don’t Repeat Yourself”, which is a methodology that encourages processing a structured data pattern (i.e. key/value for a dictionary) instead of typing more logic code (if..else) when adding more functionalities.

2. It isn’t very scalable.

Try adding a new task. You’ll have to add another indentation of if...else inside the if (authorsList.Success) condition, and you’ll also have to add an else for errors, which most likely won’t be as simple as I’ve shown.

First, make it DRY.

Here’s how you can make your code more DRY : You could use a structured data pattern. For this example, we’ll use Tuples !

var callGroupsAPI = new List<Tuple<Task<MyHttpResponse<DropdownValue>>, Action<IList<DropdownValue>>>>()
{
    Tuple.Create<Task<MyHttpResponse<DropdownValue>>, Action<IList<DropdownValue>>>(
        _restApiClient.obtainDropdownValues("categories"),
        (result) => {
            // Do something with that list.
        }
    ),
    Tuple.Create<Task<MyHttpResponse<DropdownValue>>, Action<IList<DropdownValue>>>(
        _restApiClient.obtainDropdownValues("tags"),
        (result) => {
            // Do stuff with list
        }
    ),
    Tuple.Create<Task<MyHttpResponse<DropdownValue>>, Action<IList<DropdownValue>>>(
        _restApiClient.obtainDropdownValues("authors"),
        (result) => {
            // Do some other stuff using said list
        }
    ),
};

I’ve made a list of Tuple objects where :

  • Item1 is of type Task<HttpResponseData<DropdownValue>>
    • You might be asking what HttpResponseData was this whole time. Simply, it’s a custom response container. It could be anything else that an asynchronous method from your _restApiClient wants to return.
  • Item2 is of type Action<IList<DropdownValue>>
    • The function we keep there does not return anything yet but expects to receive a response object as an entry parameter. You could, for example, take the list of dropdown values contained in the response and add them in the ViewBag to use them in your view.

Then, scale the processing.

Here’s the tricky part. We’re gonna have to use this data structure in a generic way. This will ensure of its reusability, entensibility and having to write the same instruction multiple times, which helps with readability.

MyHttpResponse<DropdownValue> result;

await Task.WhenAll(callGroupsAPI.Select(x => x.Item1));

foreach (var callGroup in callGroupsAPI)
{
    if (callGroup.Item1.IsFaulted || callGroup.Item1.IsCanceled)
    {
        throw new Exception("One of the API calls has resulted in an error.", 
            callGroup.Item1.Exception);
    }

    result = callGroup.Item1.Result;

    if (result.Succes)
    {
        callGroup.Item2.Invoke(result);
    }
    else
    {
        ViewBag.Error = result.Message;
        break;
    }
}

Understandably, this is a lot to take in. Let’s go step-by-step with this snippet.

1. Declare the result

We declare a result object for convenience. ‘Nuff said.

MyHttpResponse<DropdownValue> result;

2. Await all the tasks

Here, we await all the tasks at the same time by doing, for convenience, a quick LINQ query on Item1 of each Tuple. This is necessary in order to “activate” the asynchronous tasks within each Tuple.

await Task.WhenAll(callGroupsAPI.Select(x => x.Item1));

3. Go through every callGroup

foreach (var callGroup in callGroupsAPI)
{

Remember that var is of type Tuple<Task<MyHttpResponse<DropdownValue>>, Action<IList<DropdownValue>>>, which is quite a mouthful, I admit.

4. Check for issues once it’s done.

if (callGroup.Item1.IsFaulted || callGroup.Item1.IsCanceled)
{
    throw new Exception("One of the API calls has resulted in an error.", callGroup.Item1.Exception);
}

Since the Task object contains the state of their respective asynchronous process, we don’t lose any of the context from doing the previous await on every Task object; We just have to check their status, and if they failed, we throw an exception using the Task object’s internal exception.

By then, it will wait for that first task to be done before it gives us a result, but while this is happening, the other tasks could be still running (or be done by then), which is exactly what we want !

5. Keep the result

Protip: The previous step’s throw gets us out of our for loop if it ends up true, so no need to use a else statement here.

We can just add the result (which we should have by now) to our temporary result variable, for convenience.

result = callGroup.Item1.Result;

6. Reach for success

This is the cool part : We manually call Invoke() on the callback contained in Item2 for the current callGroup, but we pipe in the response directly. Thus, every async call does its own thing it needs to; The instructions were declared in each Tuple’s second item!

if (result.Success)
{
    callGroup.Item2.Invoke(result);
}

Do note, your mileage will vary on how you’ll check for the API’s success; MyHttpResponse<T>I is a custom object I send and deserialize from every REST API calls done in this project, but you could use a System.Web.HttpResponse just as easily and then deserialize the body. This is out of the scope from this lesson, however.

7. If all else fails…

In case the boolean indicating for success returns false, we indicate that by adding the error message from our result object.

else
{
    ViewBag.Error = result.Message;
    break;
}

The break keyword is for quitting the for loop, so we can show the error in our view without wasting any more time.

Feedback

I’d like to get as much feedback as possible for this tutorial, I’m new to writing here and I’ll be honest, English isn’t my main language. If there’s anything that didn’t make sense with the way I phrased things, or anything else, feel free to tell me about it in the comments, I’ll adapt for my next articles.

Thanks for reading, and I hope you learned something new !

Your codebase is like your house.

Today, I was reading my LinkedIn feed, trying to find some inspiration, and I came across a post describing code reviews in a way I never thought before.

The post talked about how you should treat the codebase as if it was your house, which sounds profoundly asinine at first, but… is it really?

I’ve found some good wisdom from this post and I wanted to expand on it. But first, let’s take a step back.

Imagine you’re renting an appartment. The floor and walls are old and door hinges haven’t been fixed in a while but they still can pivot.

You sign the paperwork, get your furniture in, and everyday you will get inside and live in it. As time goes on, you will keep on adding more things in it, sometimes consciously or unconsciously. Those things can be the unread mail piling on, unfinished drinks that were left on your coffee table, the bookshelves slowly filling with dust, the trash bags filling in with smelly shrimp outer shells, the dirty cauldron you used for that delicious chili you’re so proud of, the leftovers of said chili you left in the fridge for way too long…

All those things will inevitably happen as you spend time living in your home every waking moment. And while you could pay for services that will reduce or mitigate the problems (ex. deliveries and cleaning), you still haven’t fixed the core problem : You.

Yes, you. Your habits in spendings, for social and pleasure, your discipline, your anxiety, and maybe even your alcoholism or drug habits. Those are the key points why you’re not taking care of these issues. It’s not the landlord’s fault nor is it your roommate’s, despite feeling the need to blame that landlord for selling you that house or the roommate for not doing anything about it and setting a precedent. Responsibility must be taken by someone, and that someone is gonna be you, because it is your house after all.

You might be thinking “Well, I still am able to live here, and to do my daily routine and make it feel like home” but soon you’ll find you have a sink tap that seldom unlocks from its inner mechanism, the water runs on both the bath and shower resulting in lower pressure from the showerhead, or the wall-hung coat hanger that unbolted itself from the wall due to having too many coats pulling outward, so your only solution is to leave your winter coats on the living room chairs…

Ignoring the problems will probably win your more time for relaxing and living in your home without worries, but those debts will only keep increasing and causing more compromises to be made.

And then you invite people over.

If you don’t keep your home clean when they arrive inside, they’ll see it instantly. And they will understand where your priorities are.

Fortunately, in the context of code reviews, they will be more willing to give feedback, but in both cases, the fact you invite people over to look at your code or spend time at your crib will make you care more about your work.

Essentially, this has been a core issue I felt about every work contracts I’ve had for the past year and a half. All were under monolithic codebases that focused on delivering business value and rarely ever cared about ensuring the next guy who reads the code feels “at home”, because not a lot of people really did code reviews.

Add that I forced myself to work extra hours to fix issues that were ommited by past contributors/tenants and I was on a prescribed 40mg dose of Adderall (a drug that helps with my ADHD but at 26 years old only really makes me grumpy, anxious and force myself to ), to say I felt miserable would be an understatement.

And then they let me go because I had enough and used a loud drill to attempt at fixing those issues, which none of the other tenants were happy about.

Code quality is like keeping your home tidy. It’s important.

By the way, I’m a young developer who’s looking for work in Québec City and in a year around Dallas, TX. Hit me up with offers if you want me in your team !

This simple LinkedIn Hack could help you reapply to past job offers

While cleaning up my LinkedIn connections from ones I don’t interact with anymore, I noticed something that happened quite a few times more than I expected.

When you remove someone from your contacts, they get a notification that you saw their profile. This can be both a curse and a blessing.

When they check out your profile, they might remember you because they don’t go too much on LinkedIn and still remember you, and wonder why you removed them and be confused as to why you’d remove them. That’s the curse.

But what about…

When It’s A Blessing

A lot of the people who use LinkedIn do so in order to either get a new job or to recruit new employees to their job. The latter, you might already know, are called Head Hunters.

Contrairy to what’s divulged by their title coming straight from a post-apocalyptic novel, all they want is to find the best person to join their company. (and they hope it’ll be you !)

When you lack options because all the jobs you find are senior-level and you’ve freshly-graduated, a headhunter is your best pal on this battlefield that is the job market. They’re your friends. Ok, not that close, but you can often trust them to help you.

Years pass, and after connecting with so many of them, they often will forget about you. There really isn’t a nice, convenient way to say “Hey, look at me, I have lots of experience now, I’m qualified !” without sounding like an ass. Until…

A Second Chance

They look back at your profile. And to do that, you look at theirs. And if they’re interested by the skills you acquired since they last pinged you, they’ll want you to tell them you’re interested in an offer.

But sometimes, you need to validate that they want to see if you’d be a fit for their employer.

That’s why you have to remove them as connection on LinkedIn. If they add you back, you know it’s ok to message them. Conscent is given clearly that way. From that point on, it becomes easier to re-initiate a dialogue.

It might not work for everyone, but this became a revelation when it personally happened to me a couple times over the past week while cleaning up my connections. Some of them even replied back to me ! Hopefully, it helps you too.

Cheers !