• Cheapskate beginners guide to switching from hands-on web development to WordPress

    Cheapskate beginners guide to switching from hands-on web development to WordPress

    This post is the third in a three-part series about migrating from a self-built PHP-based Laravel backend to a managed WordPress backend, in an attempt to minimize on-going maintenance and custom code.

    Part one discussed why moving to WordPress felt like a visit to the Ferengi homeworld, and part two detailed what motivated the switch.

    Having previously discussed why someone might want to make a switch from a custom-built website to WordPress, and the initial experience thereof, it’s high time to round off with some practical advice for others in the same boat. In this article I’ll list the early resources I found the most useful for getting an all-round understanding of WordPress.

    The advice in this post is intended for someone who:

    • Has experience as a website back-end developer.
    • Wants a content management system (CMS) to host both hand-crafted pages as well as an on-going blog.
    • Has chosen WordPress as this CMS, but has never used it before.
    • Wants to focus on content, rather than the backend, i.e. minimize on-going maintenance and custom code.
    • Wants to minimize on-going monetary costs.

    Before we get to the list of free resources I found most useful in making the transition, let’s talk a bit about the hosting environment first.

    Hosting environment

    Although it’s more effort, I recommend separating your domain registrar and website hosting services. Apart from convenience and simplicity, there’s little reason to have both your domain and website managed by the same company. By keeping them separate you will have more flexibility if you need to change either of the two. Given that you’re reading this cheapskate guide, chances are, you’ll appreciate this flexibility down the road.

    Neither of my two domains are currently burdened by massive popularity, so I prioritized an affordable low-end solution, which could potentially scale. I narrowed my choices down to:

    • Cloudways – A cloud-based hosting solution with granular hardware scaling.
    • Hostwinds – A more traditional hosting solution.

    Since we’re cheapskatin’, we’ll be comparing Hostwinds’ cheapest option with Cloudways’ cheapest option.

    I have 2 domains, which means with Hostwinds, it’d have to be the advanced shared hosting for ~9 USD (without tax), and ~8.50 USD (without tax) at cloudways for the absolutely cheapest cloud hardware.

    Despite hostswinds offering unlimited bandwidth (compared to cloudways’ 1 TB limit), I opted for Cloudways as I preferred exclusive – as opposed to shared – hardware. Furthermore, I doubt my sites would exceed their included 1 TB bandwidth any time soon. Either way, both are affordable managed options as far as I am concerned.

    In hindsight, I’m not sure I can tell the server is exclusive as the initial website load times can still be a tad lengthy ~800ms. Then again, I did opt for the cheapest cloud hardware, and I’ve not spent hours digging into this response time.

    Amazing WordPress resources

    Due to the extreme popularity of WordPress, an enormous ecosystem has established itself around it. An ecosystem very eager to offer goods and services in exchange for money. A thriving ecosystem is great, but if you’re on a tight budget, or just getting started, it makes sense to start small and see what you can do, without paying for optional add-ons.

    Similar to how, when you’re just getting started with guitar lessons, you don’t go for the diamond encrusted Fender Stratocaster. You start with a solid used guitar. Reasonable. Sensible.

    Using wordress

    Given that our world largely runs on capitalism, you will have to do a bit of digging, as both search engines and video platforms prefer surfacing the most eye-catching sparkly content. Luckily, I can save you a bit of digging time.

    Buried underneath dozens of catchier thumbnails and titles hides WordPress’ own YouTube channel with a paltry ~22k subscribers, at the time of writing. I’m not surprised that their content is largely overlooked by YouTube’s recommender engine when competing against an avalanche of O-mouthed tech-influencer thumbnails.

    But when you finally do find their channel buried under all the attention-absorbing gunk, you’ll find numerous videos that serve as a good introduction to building website basics with vanilla WordPress. The keyword here being vanilla, without any paid exotic themes or plug-ins.

    Two videos I found very useful were…

    Builder Basics: Building with Columns, Groups, Rows and Stacks

    A great starter video which – as the name implies – explains the basic building blocks in WordPress. It also has a few slightly more advanced examples where the presenter adds some custom CSS. A great way to figure how far the so-called Gutenberg editor can take you, before you need to hand-craft some code yourself.

    Rapid Website Recreation

    A more recent video show-casing how to re-create a fairly simple photo portfolio website using WordPress. Again, very helpful in showing just how far the default Gutenberg editor in WordPress can take you, and where you’ll need to take over with custom code.

    In addition to these videos hosted on WordPress’ YouTube channel, WordPress.org also also contains numerous shorter videos detailing specific functionality I recommend watching:

    https://learn.wordpress.org/tutorials/

    All of these resources will give you an initial impression of what vanilla WordPress can do, and I strongly advise to get as much usage out of vanilla WordPress as possible. Vanilla WordPress functionality is free and is likely to be more long-term compatible, than third party plug-ins.

    But let’s say you need more, and judging by what I’ve seen in vanilla WordPress, I’m certain you will. Eventually. Then what?

    Additional functionality

    The simplest, most standard add-on functionality comes in the form of either:

    • Themes – Styling, layout, and related functionality.
    • Plug-ins – Front-end and back-end functionality.

    In terms of a theme, I opted to use WordPress’ default “Twenty Twenty-Three” theme and customize it to suit my needs. I don’t have much advice re. themes other than to note that the most popular, best supported ones, are subscription based. So if want to keep a tight budget, start out with the default theme and see how far you can get with your used guitar.

    In some cases, WordPress and its standard theme simply didn’t cover my need and I’m delighted that among all the paid options, a collection of free gems were waiting to be discovered.

    Here are all the free plug-ins that I found and installed in addition to the defaults provided:

    • Email encoder – I have a strong personal dislike for using website-based forms, just to send somebody an e-mail. But I acknowledge that if you use raw e-mail addresses anywhere on your site, at some point a bot will come crawling, scoop it up and start spamming it. This plug-in makes life a little bit harder for the bots by scrambling raw e-mail addresses using Javascript.
    • Nested pages – If your website has more than ~7 custom built pages, i.e., more than the standard About, Blog, Contact, etc., then this plug-in allows you to add much needed structure by nesting pages under others.
    • Query monitor – Admittedly, I’ve used this plug-in very little. But I expect it to come in handy in the future. It helps track down performance issues with your site, among other things.
    • Responsive Lightbox & Gallery – In addition to offering very functional lightbox and gallery functionality, which most websites end up needing, it also adds more features to WordPress’ somewhat sparsely featured media manager. I should note that some of this additional functionality appears a bit buggy, e.g. ‘filter by folder’ seems to kind of come and go, which I’m assuming is a bug. But even so, the plug-in remains incredibly useful, even in its free incarnation.
    • Loops & Logic – Although WordPress offers some dynamic presentation blocks, they are fairly limited. I find it a tad cheeky that some dynamic behavior I’d consider to be almost universally useful is available if you host via WordPress.com (not .org). This plug-in allows you to craft some useful simple dynamic behavior, like listing a selection of page links in a nice little loop.

    Hopefully this write-up has helped you a little bit on your own WordPress journey. If so – please feel free to share it with others.


    Bonus: Dynamic content

    A reader from Hacker News expressed an interest in knowing more about how Loops & Logic solved listing the newest blog posts on my site. I mistakenly recalled Loops & Logic to be part of my solution, when the actual solution involved WordPress’ vanilla ‘Query loop’ block. Loops & Logic was instead used to display a series of tagged project pages, as teaser links on the blogs front-page.

    My poor memory is as good a reason as any, to briefly cover both approaches to dynamic page content in WordPress.

    Approach 1: Query loop

    Whenever possible, leverage WordPress’ vanilla feature set, as it (again) likely has the greatest chance of long lasting support, compared to third party add-ons.

    Inserting WordPress’ Query loop block is straight-forward, and needs minor configuration to limit the number posts it displays, explained in detail here.

    The appearance of each post-preview can then be tailored as needed within the Query loop block using WordPress’ default editor.

    Approach 2: Loops & Logic

    Loops & Logic provides a set of pre-written dynamic templates when you first install the plug-in and they serve as a good starting point just to get a feel for exactly how expressive the plug-in allows you to be.

    However, the samples themselves don’t do much in terms of fostering an understanding on how it all works underneath the hood, or how the various dynamic components in Loops & Logic work together. My own explict customization of their sample code entitled “Advanced – Styled blog post grid” also wouldn’t help newcomers much I fear.

    Instead, I suggest watching the same tutorial video I did, which should yield all the knowledge you need to construct the simple dynamic content I did.

    If not, reach out, and I’ll gladly provide you with my sample code personally.


  • What 5 years of interviewing software engineers taught me

    What 5 years of interviewing software engineers taught me

    From 2017 to 2023 I interviewed and evaluated over 100 C++ software engineering candidates, with the final three years also covering Python. In this article I’ll cover key lessons I learned from this experience, including:

    • Which interviewing approach we used and why I’d recommend it over Codility or similar platforms.
    • Rare cases where I would suggest deviating from our standard interviewing approach.
    • How the approach evolved over time.
    • Caveats and concerns with the approach.

    The TL/DR for the time poor reader: Test your software engineering candidates in the exact types of problems they’re likely to face, with take-home exercises, i.e. no Codility-like logic puzzles that must be solved within 2 hours.

    But why? Are there exceptions? How costly might it be to develop that take home test? For that, I recommend the full article below…

    Our interview approach

    In general, our interview approach consisted of three stages:

    1. An initial phone-interview to make a quick ~20 minute screening of a promising candidate.
    2. A take home test which typically took 4-8 hours to solve thoroughly.
    3. A final in-person interview which typically lasted 2-3 hours.

    I’m glad to say that in all my time evaluating candidates, we never made a hire that didn’t work out. In this regard, it is important to note three things:

    1. Chance is a significant factor. You can’t test for everything, and part of hiring is rolling a die. But you can try to make that die-roll as predictable as possible.
    2. Both the initial and in-person interview involved either two or three company employees, so credit definitely goes to my former co-workers in helping assess promising candidates.
    3. The ‘perfect hiring record’ could simply mean the bar was set too high, rather than ‘just right’, which is bad.

    1. Initial phone-interview

    The initial short interview is an essential step to make sure you’re not wasting the candidate’s valuable time, as much as they’re not wasting yours. Ideally, this shouldn’t be more than 15-20 minutes to…

    • build a bit of familiarity. Cover basics you wouldn’t even think of as a source of potential problems, like how well they speak the language you speak within the company. We had a few candidates that were very difficult to understand over the phone. Not enough to dismiss the notion of hiring them there and then, but enough to weigh this into the general consideration of whether to proceed to the second interview phase.
    • ask the most basic of software engineering questions, and I do mean basic. In C++, a basic question could be whether they’re familiar with smart pointers, and if they know what they’re useful for. Good basic questions address functionality that nearly every developer is almost guaranteed to have come across, using a particular language.

    I intentionally add this emphasized box, as I’ve often seen this go side-ways, particularly with technically-minded interviewers.

    The phone-interview is not the time to have the candidate find your favorite answer to a technical question (spoiler alert: It is almost never that time), but instead to get any generally correct notion of an answer, and ideally probe how deep that correct answer goes.

    Hopefully, the short interview concluded with a promising outcome and you’re confident that the candidate at least has a solid shot at passing the take home test.

    2. Take home test

    A former colleague of mine once said…

    Test what you ship, ship what you test…

    Tim Crawley

    He’s unlikely the first to coin the phrase, but it’s an excellent adage and is somewhat applicable to hiring programmers.

    Test your candidates with actual problems they’ll counter, or at least very similar ones.

    Me (and likely many others)

    This is precisely what the take home test is intended to do. In our case, we often hired computer-vision capable software engineers, and thus provided a take home test which specifically involved simple computer vision related problems, along with one or two very generic algorithmic problems.

    Each candidate was asked to implement solutions to a small set of tasks which came with a function signature we defined, such as:

    void ModifyImage( int* data, int imageWidth, int imageHeight );

    Along with some details about what the candidate could assume regarding the incoming data, very little is needed to ensure their code can plug neatly into your own custom-built testing framework. By only providing a set of sparse headers, the candidates are free to implement their solutions in whatever Integrated Development Environment (IDE) they’re comfortable with, along with whatever unit-tests they deem necessary, if any.

    Although the tasks themselves had already been determined by the time I joined the company, and barely changed in the 6 years of my employment, I spent about 6-8 weeks creating and modernizing a C++ framework to test and evaluate all the candidates solutions reducing the overall time to analyze a solution from about 14 hours down to about 3-4 hours per candidate.

    Admittedly, 6 weeks – even over the course of 6 years – is costly developer time. Depending on what your senior developers cost per week, and you do want a senior developer building the take home test, it can easily run you 11000 USD or more. But if your hiring needs are on-going, and comparing against popular testing platforms (like Codility), 11000 USD amortized over 6 years suddenly doesn’t seem so bad.

    Furthermore, I’d argue that Codility and similar platforms often come with some serious drawbacks, compared to a custom in-house take home test. Such as:

    • Needless logical reasoning – Codility and similar platforms often present coding challenges wrapped in complex logic puzzles, e.g. how do you use 10 servants to find the single barrel out of 1000, which contains slow-acting-poison, before the king’s next big ball? Unless you’re hiring developers to literally solve puzzles in 101 brain teaser books, please do not do this. I suggest problems where the general solution is readily apparent and the main focus is on the implementation itself. Our take home test did contain a small set of gotchas (one of which I failed upon being initially hired), but they were all implementation-related curve-balls, such as arithmetic overflow or iterator invalidation.
    • Unrealistic time pressure – Codility and similar platforms often provide a timed environment in which to solve problems as fast as possible, but most development work occurs without any immediately-looming running clock. It is a detrimental constraint on the test and will skew results.
    • Encourages lazy inaccurate interviewing – Codility and similar platforms appeal to clients by promising the allure of boiling every candidate down to a single comparable number, e.g. Developer 1: 72%, Developer 2: 66%. I’m sure Codility has some wording somewhere encouraging their customers to inspect candidate solutions, rather than just rely on numbers, but their landing page sure pushes the notion of simplifying your developer hiring task down to “72 > 66, so I guess we hire Developer 1?”. You may wonder why this is problematic?
      • In short, because this overall-developer-score is a questionable representation of overall performance. To the best of my knowledge, the Codility scores are (still) largely informed by two factors: Code run-time efficiency, and code correctness. Examining these factors is useful, but distilling an overall candidate score from it, is problematic. I’ve hired developers who, due to a small oversight (addressed in the follow up interview), provided a solution resulting in near 0 code correctness. I’ve also declined to hire developers who delivered nearly unreadable code that passed both run-time and code correctness requirements.
    • Unintelligible task descriptions – I’ve witnessed first-hand how some task descriptions on Codility and similar platforms are so poorly formulated, that I’d argue it was actually more difficult to understand the problem to be solved, rather than figuring out how to actually solve the problem. Mind-boggling. I’m certain this does not apply to the majority of tasks, but I believe the reason it happens at all, is because ‘hard to understand‘ can look indistinguishable from ‘difficult to solve‘, for Codility in testing. If the percentage of correct answers is low, it’s easily explained away by assuming the problem itself was just hard, rather than difficult to understand. Given that our take-home test contained the same set of tasks, we quickly took notice when two or more candidates appeared to have the same misunderstanding.
    • Environment familiarity – Codility and similar platforms all have their own user-interface that the developer must familiarize themselves with. These can, and do, get in the way of testing the candidate. Codility (and likely other platforms) know this, as they strongly encourage candidates to do a practice test before proceeding to the real one. Admittedly, this is a minor issue compared to the first four.

    Having read all those points, if you’re prone to black and white thinking, you may also be thinking…

    So you’re saying Codility is absolutely awful and should never be used, despite the fact that it’s clearly commercially very succesful given all its clones, how stupid are you?

    Dichotomous thinker

    Contrary to popular belief on the internet, it is actually possible to hold the belief that something is both good and bad in different ways. So while I’m giving Codility and similar platforms here the business, by pointing out that their ways of testing candidates aren’t very representative of real-life software engineering work, and come with significant caveats, their approach is still effective. But just because something is effective, that doesn’t mean that it’s the best approach. In a later section, I’ll denote when I would recommend using these platforms.

    One topic I will address here which often comes up when allowing any test taker to complete a test while not under observation and without a hard time constraint. The topic of cheating. First, I recommend the reader accept the fact that fully eliminating cheating is impossible. No matter how you test or what constraints you add, there will always be ways around them. The goal isn’t to eliminate cheating entirely, but rather to reduce it as best as possible. Even Codility accepts this impossibility, given that the platform has candidates agree to their ‘Code of Honour‘ promising that you don’t cheat when taking one of their tests.

    So we just throw our hands up in the air and give up?!

    Dichotomous thinker

    No, dear dichotomous thinker. In the in-person interview, we use the candidate-provided solutions as a jumping-off-point to discuss mistakes, coding style, implementation alternatives, etc. So while the take home test undoubtedly widens the candidates options to cheat by allowing them ample time to coordinate other people to solve the given tasks, they will ultimately be expected to have an understanding of the code produced, as well as why it built the way it was.

    The take home test provides exceedingly fertile ground to get an insight into how the candidate prefers to program and the follow-up in-person interview is a great place to discuss how open they are to alternate ideas and implementations.

    3. In-person interview

    Assuming the candidate passed the first two phases with promising colors, the final step consists of:

    • Discussing the solutions provided in the take home test.
    • Discussing 1-2 simple in-house developed coding problems.
    • Discussing a customer requirements situation for a in-house issue we’ve worked on for years.

    One of the great benefits of starting the interview with discussing their take home test is the candidate’s familiarity with a piece of code they’ve made themselves. Presumably it was made in their preferred environment, on their own time with as little artificial pressure as possible, and similar to a real working environment as possible.

    While I cannot share explicit examples of discussions we had in this phase, I can comment on my recommended approach to discussing the candidates provided solution.

    One important detail to discuss first, is your interviewing mindset. Consider that for the candidate, an interview scenario is very dissimilar to any day-to-day tasks or discussions they are likely to have at your company, should you hire them. Unless your candidates are often going to be seated in tense discussions with clients who are likely to challenge their solutions or suggestions, I advise keeping in mind how stressful an interviewing scenario can be for some candidates. Of course, it is still your job to evaluate promising candidates, but I advise starting with a mindset of:

    How can I help this candidate showcase the best answers they can come up with?

    Rather than:

    Let’s see if this candidate is really as good as the first two phases seemed to indicate.

    So how do we approach discussing the take home test with the former mindset?

    Based on the candidates solution’s and errors found within, I suggest having an increasing set of hints ready to narrow the problem down and see when the candidate is able to jump in and solve any problems you’ve found in their solution.

    For example, let’s look at a hypothetical – but common – iteration deletion issue in C++:

    std::vector<int> values;
    for (auto iter = values.begin(); iter != values.end(); ++iter)
    {
    	if (*iter == 10)
    	{
    		values.erase( iter );
    	}
    }

    This code is supposed to remove all values of 10 in a vector. The veteran C++ coder may have noticed the problem, namely that calling .erase() on an iterator will invalidate it, causing the code to crash.

    Assuming this code is a part of a larger solution by the candidate, an approach to discussing this iterator issue could be:

    • Question: It appears there’s a problem with the solution, causing it to crash. Do you have any idea what it might be?
      • Always start by giving the candidate the space to show off the most, i.e. with little to no guidance at all. It’s possible that they’ve looked at their solution again after submitting it and found the problem in-between the take home test and the in-person interview. If nothing comes to mind, and especially if the submitted solution is large, I suggest not dwelling here for too long. Assuming no answer is forthcoming, provide…
    • Hint 1: There seems to be an issue with a part of this for-loop. Any ideas?
      • How much to help in terms of narrowing down the problematic area is subjective and also dependent on the issue itself. My general advice here is try and hit a happy medium. Narrow too much and you’re practically giving the candidate the answer. Narrow too little and the candidate may remain clueless and feel heightened anxiety by your possible expectation that the narrowing should have helped enough. If the answer continues to elude the candidate, we provide…
    • Hint 2: When we ran the code with this set of values ([3,6,10,3,4]), it crashed midway when the iterator pointed at 10. Thoughts?
      • Notice how this hint is really narrows down the issue, and still doesn’t give away the technical reasons as for why the crash occurs. If this also fails to yield insight I recommend…
    • A renewed approach: Stepping through the code together and have the candidate explain to you what is happening step-by-step.

    The benefit of this approach is that the candidate is provided a figurative ladder from which to make the final leap to the solution on their own. Of course, the more steps – in the form of hints – they’re provided on the ladder, the less impressive the leap. By motivating a gradient of outcomes, as opposed to 100% correct or 100% incorrect, you’ll get a more nuanced idea of where approximately the candidates depth of knowledge lies, as well as providing tension relief as the candidate ideally always makes the jump to the correct solution, even if most of the steps were provided.

    I suggest informing the candidate upfront about your intention to give them hints during the discussion along with the fairly obvious fact that the sooner an answer occurs to them, the better. There are only benefits to your candidates knowing how the interview will be conducted, and it’s not really possible for them to ‘game the system’. Note that actively providing a candidate with hints does occasionally lead to a manageable side-effect. Specifically, that some candidates will be inclined to suggest solutions or ideas as questions, e.g., “Is the issue X?“, “Perhaps a solution could be Y?“, etc.

    In fairness to all candidates, I respond by asking candidates what they think, when they pose these types of “question answers”. The goal is to find the candidates committed answers, and then have a dialogue about it. Even an incorrect answer can lead to a dialogue that yields valuable knowledge. Ultimately, candidates posing questions is great, but when it comes to specific problems you expect them to understand and solve, you do want to make sure they can stand on their own two feet.

    Note, that while a candidate may muddy the waters regarding standing on their own two feet, they’re not the only source of potential ambiguity.

    You, or an eager co-worker may equally be inclined to start nodding before the answer has barely begun to leave the candidates lips. Something I’ve witnessed on more than one occasion myself. This is to be expected, since you and your colleagues will see multiple candidates step into the exact same figurative potholes.

    Fight the habit of becoming complacent and do your best to keep both verbal and non-verbal communication reserved until you have hear the complete and unique answer from a candidate. It’s possible you may already be convinced they’re a good fit, but that may not be the case for your co-workers.

    A benefit I cannot overstate in regards to having a conversation about implementation mistakes is seeing how well a candidate handles simply having made a mistake. We all make mistakes. All of us. No exception.

    The vast majority of candidates who made it to the third phase would – given the opportunity – quickly realize their error and offer a solution.

    Anecdotally, I will never forget a particular candidate who – when faced with an issue in the proposed solution – seemed physically incapable of recognizing a problem we’d found, and consequently also unable to come up with any solutions. In hindsight, I rationalize the experience with this candidate as them being most familiar with always being the expert in the room and rarely challenged on any of their solutions.

    When to deviate

    In 2012, Valve’s employee handbook leaked on to the internet. A salient point it makes is:

    […] hiring is the single most important thing you will ever do at Valve.

    Valve handbook for new employees – Page 6

    I tend to agree, that it is among the absolute most important activities for any company, which is why I’d be wary of modifications to the outlined interview approach, born out of an interest to lower costs. Hiring is one of the last places you’ll want to cut corners given the catastrophic consequences a bad hire can cause a company.

    That being said, here are some possible scenarios for deviation.

    Lack of resources or rare hiring

    If you find yourself unable to convince management that hiring really isn’t the place to spare resources, or find that your hiring interval easily exceeds a year or more between hires, then I suggest either one of two method variations:

    • Ditch the in-house testing framework – Source your take home tasks from online sources, possibly even Codility or other testing platforms. I still recommend providing the tasks as take home tests rather than online timed tests to avoid the negatives listed earlier. While this approach has a lower upfront cost, it will instead take more time to properly analyze and evaluate each candidate, as you’ll be doing more manual work there.
    • Ditch the take home task – Save even more resources and rely fully on a cheap start-up Codility knock-off variant. If you absolutely must use such a platform, I recommend keeping all the previously mentioned downsides in mind:
      • Needless logical reasoning – Generally pick the easiest problems they provide so you focus on your candidate’s implementation skills, as opposed to logic puzzle solving skills.
      • Unrealistic time pressure – Turn off the running clock if possible.
      • Encourages lazy inaccurate interviewing – In addition to the platforms performance evaluation, make sure you inspect the solutions your candidates to create yourself. You have much to gain from not relying on the single-digit evaluation of the candidates you test.
      • Unintelligible task descriptions – Familiarize yourself with the problems you picked and try solving them yourself.

    Culture hire

    The outlined approach focuses on determining a candidates technical skills. It’s worth at least a single paragraph to emphasize that there are times where the best hire for the company, isn’t the person who excels the most in a technical capacity. Sometimes, the best hire you can make is the employee that can help shift troublesome company culture in a positive direction.

    Simultaneously, it is also a grave error to hire an exceptionally technically talented individual who’s personality clashes with the existing team, or simply has difficulty recognizing issues in their own work, as an earlier anecdote described.

    But culture-related hiring concerns is beyond the scope of this article, and probably deserving a wholly separate article, on their own.

    How our approach evolved

    Our interview approach was refined over the course of five years, but fundamentally remained the same. The biggest refinements include:

    • Automation – When I initially assumed my duties as candidate evaluator, it was mostly a manual task and took 1-2 days to fully test and analyze a candidate’s solution to the take home test. Building an in-house test framework reduced this time down to about 3-6 hours per analysis, depending on the solution. Well worth the 4-6 week investment of developer time to streamline this critical and ever re-occurring task.
    • Standardization – Automating the testing of the take home test also required more standardization of the test itself. While we generally preferred to give candidates as wide a berth as possible when it came to implementing their solutions, I would recommend some structural limitations such as requiring the implemented solution to fit a specific function signature.
    • Task description evolution – We encouraged all candidates to ask for clarification if something was unclear, and multiple candidates asking the same question was a dead giveaway that our task description required further clarification.

    No matter how clear and explicit you are in your task instructions, some candidates will end up overlooking some details.

    Our internal policy was to fix minor formality issues if necessary, but if anything took more than a couple of minutes or pertained to the implemented solution itself, we’d simply push the solution back to the candidate with a note on what remains unfinished.

    In terms of technical limitations, we very intentionally did our best to only require the minimum it took for a candidates solution to neatly plug in to our in-house testing framework. Our reasoning being that we deliberately want to see a candidates design approach to solving a problem, in addition to the actual problem solution itself.

    Admittedly, by eventually requiring candidates to inherit from our abstract C++ object, we’ll never again see submissions with code written and submitted in a Word (.doc) file. I do miss those days. On the bright side, it didn’t prevent us from receiving a submission containing so many syntax errors that nothing could compile. Upon inquiring about the errors, the candidate told us they felt using a compiler was cheating.

    Caveats and concerns

    With soft problems like hiring, no approach will ever be perfect. Here are the caveats the outlined interview approach:

    • High use of candidate’s time – For any candidate who passes the initial phone interview, it can require a full day of their time to solve the take home test. I’d suggest offering candidates compensation for this time investment. Most companies are unlikely to do so.
      • Note that this caveat also applies to Codility and similar platforms. Although most Codility tests I’ve taken set the time-limit to two hours, considering the amount of prep-work I’d recommend anyone taking a Codility test to do, it quickly becomes comparable to take home tests.
    • High use of resources – If I worked for Codility, this would be the drum I would bang. “Your developers time is too valuable to spend on interviewing! Let us handle this tricky task and you can just focus on whatever it is your awesome company does!“. Do not fall for this tempting line of thought. Hiring is one of the most important tasks you’ll ever do. Yes, the outlined approach requires actually investing time in the candidates solutions, but that’s where an in-house testing framework can cut that work down to a manageable size.
    • Limit the number of judges – A tangential point to the outlined approach, but I still feel strongly enough about to include. I recommend limiting the number of people you involve in the hiring decision, as my impression from interviews with other companies, is that there’s a trend towards the opposite.

    Finally, I thought it prudent to think of some concerns I might have, had I not spent all this time using the approach:

    • Cheatability of take home test – Given that we rarely varied the tasks given to hopeful candidates, a point can be made that we open ourselves up to rampant cheating. Keeping in mind the aforementioned assertion that eliminating all cheating is a pipe-dream, we intentionally had the initial phone screening as a barrier to avoid needlessly providing our test kit. Furthermore, the in-person interview dug so deep in the provided solution that if the candidate hadn’t written it, they’d have to have spent a significant portion of time familiarizing themselves with it and why it was built they way it was, making the whole effort to avoid time spent writing it in the first place irrelevant.
    • Not enough judges – As hinted early on in the article, a maximum of typically three people interviewed the developers we hired. Other people, including Joel Spoolsky – who’s article on interviewing I largely agree with and highly recommend – would assert that three is too small a number. My impression, from being interviewed at other companies, is that there is a trend towards a higher number and I generally caution against it. Personally, I think both diffusion of responsibility (“If things go side-ways no one person is at fault.”), and the thought that each additional interviewer is additive (“Best get everyone’s input on this!”), attracts companies to this decision of increasing the number of interviewers. I’d do not agree with the latter, and at the risk of sounding like a broken record player, I caution against increasing the number of involved individuals in a hiring decision. I’ll leave finding the exact right number for you, to you, and possibly a future article.

    Phew…

    If you got to the end, I appreciate your attention and thank you for taking the time to read my ramblings. I hope you’ve found some value in the article and all the best with your interviews and interviewing!


  • The virtue of selective ignorance and why I finally switched to WordPress

    The virtue of selective ignorance and why I finally switched to WordPress

    This post is the second in a three-part series about migrating from a self-built PHP-based Laravel backend to a managed WordPress backend, in an attempt to minimize on-going maintenance and custom code.

    Part one discussed why moving to WordPress felt like a visit to the Ferengi homeworld, and the final part of the trilogy will round out what recommendations I’d give to other developers migrating to WordPress.

    If you enjoy knowing how something works, then you and I, are cut from the same cloth. I want to know it all. The more I know, the better I can work with something and understand precisely how to use it in the most efficient way possible.

    But knowing everything is a fantasy. Much like a good Steven Seagal movie, it’s never going to actually happen. Even the seemingly most simple things can have a near endless depth hiding behind it. Take, for example, setting the a variable to the value of 1, in C++:

    int variable = 1;

    This seemingly simple instruction can easily have layers and layers of complexity hiding behind it. Like how the variable – or more accurately – the space in memory representing the variable, is allocated and assigned, i.e. heap and stack. Another layer of complexity to explore is whether the variable is ever actually memory-allocated and set during execution, depending on the which settings the C++ compiler had set during compilation, and which of the many C++ compilers was used. The memory allocation and assignment instruction may be optimized away.

    The point is: Whether I want to acknowledge it or not, it is literally impossible for me to understand all the concepts I would like to understand, to the depth I would prefer. While I’m sure that the ever shrinking amount of free time I have as an aging adult contributes to this feeling, I think the real accelerant has been gaining deep knowledge in about 3 or more fairly separate fields of technology.

    So what do you do? If – like me – you’re a strong believer in skill stacking you definitely do not want to reduce your areas of specialization. If skill stacking is an unfamiliar concept, I urge you to read Tomas Pueoy’s article about it. The gist is: It’s nearly impossible to become the world’s best at one single skill, but it’s quite possible to become the absolute best at a combination of skills, particularly if the combination of skills don’t tend to go together. The key is to find the skills that do not tend to go together, but still compliment each other well, e.g. programming and public speaking. Honestly, if you’ve never read Tomas Pueoy’s article, it is a better use of your time, than reading my own word salad. Feel free to leave, become wise, and then when you’re ready to continue slummin’ it here with me, I’ll see you then.

    All caught up on skill stacking? Great!

    Having solidified that we don’t want to drop any field of expertise as a whole, how do we determine what to become selectively ignorant of?

    I suggest any sufficiently complicated tool you don’t use often enough. Vague, I know. What’s not often enough, and what if I suddenly need this tool unexpectedly again? While I cannot help predicting the latter, I can comment on the former. “Not often enough” is contextualized by all the complicated tools you use in life. Somewhere, in your every-day activities, is one or more tools that you use the least, and is far more complex than all the others you use just as little. That’s a good place to start.

    Allow me to break my own motivation for embracing selective ignorance into bullet points, with minor examples relating to my old – now retired – custom-built PHP-based Laravel back-end:

    • Knowledge degradation – Our memory is ever fading. I acknowledge this upfront as it is a core component of why the upcoming points end up being so problematic.
    • One-off tasks – Tasks that need to be dealt with once a year. Building a custom PHP/Laravel website back-end, running on a local virtual machine, is choc full of one-off tasks, particularly during the initial scaffolding setup. You don’t think much of this until much later, when all of a sudden you need to touch some of this scaffolding again. But by then, you may barely recall the details. How exactly did I stop/start this obscure service that occasionally fails via SSH again?
    • Evolving tools – Most tools evolve over time and we must learn to keep up with the changes or become unable to effectively use them. Different tools evolve at different speeds, e.g. web standards and associated tools generally evolve faster than tools for desktop applications.
    • Growing expectations – As a craft grows, so do expectations. Website visitors have higher expectations these days, compared to the heady early internet days in the 90s. If you want to maximize your ability to meet these expectations, you’ll need to commit a huge amount of time to keep implementing and maintaining features, or make use of middleware.

    Your milage for these points will – of course – vary, depending on which type of technology you’re considering turning the other cheek towards.

    A reasonable counter-argument to the first two points is documentation. You can document the most esoteric knowledge you accumulate, and there are numerous platforms available to host a small knowledge base for free. But make no mistake, documentation is more work. Documenting a process only for yourself is a large overhead for a limited benefit. Good documentation takes a long time to write, and the only reader, would be you.

    The last two points highlight the growing complexity the web offers. You can choose to opt-out of new features/standards and risk alienating visitors, put in more effort, pay someone else for the effort, or reach for middleware. Those are basically your options when it comes to the web.

    My own embarrassingly overdue epiphany came about when Google’s chrome, and most other browsers, opted to label all non-SSL sites as unsafe in 2017. Despite reassurances from some developers (see warning further below), that transitioning from http to https was a small task, I felt deep down that this was actually the last of many tasks that finally broke my own back.

    Even if the task was small, and by small I mean one that would merely take a day, for the unseasoned virtual machine host to implement, there would always be more ‘never seen before’ tasks. Many of these, as previously noted, would be near one-off tasks, never to return, until right about when the last vestigial thread of knowledge for that one-off task has left your brain. Then, and only then, would the task make its triumphant return, maximizing the amount of time you must spend getting back into the right knowledge context to address it.

    An important note regarding well-meaning developers who may give you advice regarding the amount of time it takes to do ‘something‘. Take their advice, with an Everest-sized amount of salt, I cannot stress this enough. Particularly if this advice is given without the slightest of initial queries regarding the circumstances in which you are to do this ‘something‘.

    Given the amount of times this has happened to me, I thought it worth highlighting: Other developers do not know your circumstances, but will still be eager to tell you exactly how simple or quick something is to do. Even worse, a small portion of these developers will dismiss or argue any facts you provide to clarify why – in your situation – it may not be so simple after all. Almost as if, once this type of person has taken a stand on “It’s a 5 minute job tops“-hill, that is where they must die, regardless of any later revelations that would actually completely change the situation. Where the opinion started, so it must end.

    So if you wish to run a standard website offering many contemporary conveniences and neither your paid work, nor your core hobby activity is webdesign – and possibly even then – pay someone to help. If not, I’d argue you run a high risk of finding yourself often having to spend a surprising amount of time re-learning context, dealing with multiple one-off tasks, or otherwise risk the website deteriorating.

    The 10-15 USD you’ll be spending a month is well worth leaving the back-end tools behind, which you’ll rarely use, yet must always be somewhat up-to-date with, in order to keep your website from falling behind or off a cliff.

    If you’d also like advice on how to make the transition from a more hands-on approach to a managed WordPress solution, tune in again next week for the final part in this series, same bat-time, same bat-website…


Projects

LyricManager

Aligning lyrics to audio is the task of determining the precise time in a song when each individual word is being sung, i.e. the start…

PlanMixPlay

The elevator pitch for PlanMixPlay is a more engaging way of delivering an audio and video performance. More than 8 years in the making, PlanMixPlay…

TapDrag

After spending countless sessions interacting with a larger sized touch display, i.e. ~30 to 50 inches (approximately 3-5 times larger than a modern IPad), we…

Icon Set Selection via Human Computation

Icons have long been a cornerstone of GUI design, ever since the emergence of WIMP (Windows, Icons, Menus, Pointers) by Xerox. Given the “Mobile App…

lasselaursen.com

A younger me would have scoffed a bit at the idea of labeling my own website as a project worthy of mention. Now – on…

Post-it Art

In early 2013 I found myself on the receiving end of a break-up and a sudden abundance of free time on my hands along with…

DJ Interface with Remote Audience Feedback

Streaming live performances is common place these days. While the technology to deliver the performance has massively improved over the past years, the methods with…

Registration-based Volumetric Interpolation

Volumetric rendering has come a long way since its first appearance decades ago. Graphics cards have been subject to massive technological advancements and are still…

3D Texture Synthesis

Texture synthesis fascinates me. Particularly 3D texture synthesis because as opposed to 2D texture synthesis, there isn’t a simple alternative to capturing data. To obtain…

Virtual Cuts

Pork is big business in Denmark. Tiny improvements on each individual product translates into several million dollars saved. In 2009, a growing interest in product…

GazeTrain

My previous augmented reality (AR) based project caught the attention of COGAIN. COGAIN focuses on promoting research and development in the field of gaze-based interaction….

Computer aided board-gaming

When I was first exposed to augmented reality, I couldn’t help immediately thinking about how it could be applied to games. I was intrigued by…

GPU Bee-havior

Prior to Nvidia’s public release of CUDA, programming a state machine using graphics shaders was challenging, but certainly not impossible. This project was among the…

Dolores

Dolores is a total conversion modification for Half-Life 2, released in March 2006, as part of the Danish academy for digital interactive entertainment (DADIU) graduation…