Navigate back to homepage - Caricature image of Ryan Tyrrell

Hi, I'm Ryan!

I build web sites & apps for entertainment brands

When is a resource not a resource?

I wanted to share a story about resourcing. I am personally not a fan of the word "resource" to describe a developer or designer tackling a problem, as it encourages the thinking that people in these roles can be "swapped out" on a project.

A while back, I worked on a project where our client requested a change to some copy on their web site. The team who originally built the site had moved on from the project and were off doing other things, so a decision was made to ask a different developer to make the change instead. The task was to update the text:

"Your media is transcoding..."

to:

"Your videos are transcoding..."

On the surface of it, this seems like a trivial change. It's a simple "find and replace" task, right? This could be done by anybody who knows how to perform a search, update some text and push the change to version control... The project manager agreed that this update could be made in a matter of minutes and that it would be pushed to the live site by the end of the day.

Here's the steps the developer took, and how the task spiralled in to taking over two days:

1. Search the codebase for the text

Five second job? Nope. Searching for the full text string didn't return any results. Neither did searches for the text "Your media". Searching for the word "transcoding" returned dozens of results, one of which looked promising:

<?php
// resources/lang/en/transcoding.php
return [
    'please_wait' => 'Please wait...',
    'transcoding_in_progress' => 'Your :content is transcoding',
];

Ok, so it looks like there is some localisation going on here, and in the English language we want to use "Your :content is transcoding". But what is this ":content" thing? Looks like a variable. It seems that this project uses the Laravel Framework, and a read of the documentation shows that variables can be passed when using the language translation helpers. Ok - so this is the thing that powers the line of text I want to edit. But where is is being used?

2. Find where the code is being translated

The Laravel localisation documentation suggests that the way to make use of the localisation helper is via the "&lang" helper or the "__" helper. A scan of the codebase reveals around 200 uses of these helpers. So the developer tries searching for "&lang('transcoding_in_progress'". No results. "__('transcoding_in_progress'" - No results. Ok, so just "transcoding_in_progress". Nothing.

Is this translation function even being used at all? Maybe in this instance the text is being created in another manner? To figure this out, the developer needs to inspect where this is being used in the web site. The developer doesn't have an account on the live site, and would need to go through an approval process to test content uploads, so instead decides to set up the project locally. This involves creating Docker containers, configuring environment variables, the lot. Two hours later, and we're ready to debug:

3. Figure out how the text is rendered

After granting the required permissions on the developer's copy of the codebase (thankfully this project is well documented for developer quickstart), we're able to test content uploads. By inspecting the web site using developer tools, it looks like there is an "overlay__title" class on the text element we're looking for. After further digging, we see that in the JavaScript layer there is an overlay module, used to display prompts like this to the customer. Brilliant. So the developer reads up on the overlay module and figures out that the text we're trying to edit is being passed in to the overlay module's "renderTitles" method.

// resources/js/components/overlay.js
const renderTitles = function(title, subtitle) {
    let titlesHtml = '<h2 class="overlay__title">' + title + '</h2>';
    titlesHtml += '<h3 class="overlay__subtitle">' + subtitle + '</h3>';
    return titlesHtml;
};

Digging deeper and we find the source of how our text is being displayed. It's in a "handleTranscodingStatusUpdate" method, within the "uploader" module:

// resources/js/components/uploader.js
const handleTranscodingStatusUpdate = function(newStatus) {
    if (newStatus !== currentStatus){
        overlay.show();
    }
    if(newStatus === 'transcoding-begun'){
        const title = langHelper.get('transcoding.transcoding_in_progress', {
            content_type : langHelper.get('content_types.media')
        });
        const subtitle = langHelper.get('transcoding.please_wait');
        overlay.setTitles(title, subtitle);
    }
    // More logic here...
    return true;
};

Right, so it looks like there's a way to use our translations in JavaScript as well. This also suggests that the word "media" is set in a different language file called "content_types". After checking, we find that this is indeed the case:

<?php
// resources/lang/en/content_types.php
return [
    'audio' => 'audio',
    'movie' => 'media',
];

So it looks like whoever created the language files knew that we were working with "audio" and "movie" content types, but movie has been known as "media" up to this point. Now we simply need to change the movie content type to read "video" instead of media and job done. Ah, but then the text would read "Your video is transcoding". This isn't what we're after, as users can upload multiple videos. We now need to consider pluralisation.

4. Handling pluralisation

Up until now, using only "audio" and "media" as our content types has meant we did not have to consider pluralisation, as the plural of "audio" is "audio" and the plural of "media" is "media". Now we're changing this to be "video", we need to consider "videos" as well. Ok, so we'll allow for pluralisation in the language files:

<?php
// resources/lang/en/content_types.php
return [
    'audio' => 'audio',
    'movie' => 'video|videos',
];

We also need to update the transcoding text to use "are" instead of "is" when we're transcoding more than one video, i.e - "Your video is transcoding" / "Your videos are transcoding":

<?php
// resources/lang/en/transcoding.php
return [
    'please_wait' => 'Please wait...',
    'transcoding_in_progress' => 'Your :content is transcoding|Your :content are transcoding',
];

Ok, so now an update to the JavaScript to account for these changes. When we update the transcoding status of our uploaded video(s), we now need to know how many videos are being transcoded so we can show the correct message:

// resources/js/components/uploader.js
const handleTranscodingStatusUpdate = function(newStatus, numberOfItems) {
    if (newStatus !== currentStatus){
        overlay.show();
    }
    if(newStatus === 'transcoding-begun'){
        const title = langHelper.get('transcoding.transcoding_in_progress', numberOfItems, {
            content_type : langHelper.get('content_types.media')
        });
        const subtitle = langHelper.get('transcoding.please_wait', numberOfItems);
        overlay.setTitles(title, subtitle);
    }
    // More logic here...
    return true;
};

Job done. So now let's see what happens when we render the page... No change. Why not?! We dig a little deeper...

5. Why is it not "just working"

We discover that the PHP language files are duplicated in the JavaScript layer in a file called "lang.js". The developer copies the new translations over to the JavaScript file and tests the feature. Looks good - uploading one video results in the overlay displaying the text "Your video is transcoding", uploading two videos prompts that "Your videos are transcoding". We're done here.

The developer commits the code to version control and pushes to the external code repository. Five minutes later they receive an email saying that the automated build they just ran has failed due to "language files being out of sync on the front end and back end". What does this mean?!

6. The failing tests

Right, so after reading the error messages in the failed build process, we discover that the JavaScript language file is actually created in a compilation step, via a third party tool. The previous developer had written an automated tests to check that the PHP and JavaScript language files were always in-sync with each other to ensure translations on the back-end are always the same as the front-end.

The developer discovers that they need to install the projects npm dependencies in order to compile these translations. They run "npm install" and realise they need to update their local version of npm in order for things to work. So they install node version manager, as they need to continue using an older version of npm for a different project. Ok - everything is running. After following the documentation of the third party tool, everything seems to work as needed. Brilliant.

7. Unrelated features are now broken

Upon testing the site after this feature has shipped, we notice that other features are breaking. In the profile area where it used to say "Your uploaded media lives here", we now have an empty box. Another page in the profile area won't load at all. After checking the logs and running debug tools, we realise that our seemingly trivial code update has had a knock on affect. Anywhere across the site where the "movie" translation was accessed now needs a revisit, as we've introduced pluralisation. The code that rendered the "Your uploaded media lives here" text assumes no pluralisation is needed:

// resources/views/profile.blade.php
<h3>{{ __('profile.content_list', [
    'content_type' => __('content_types.movie'),
]) }}</h3>
<ul class="content_list">
// content list goes here...
                

So we change this to allow for pluralisation of the content type:

// resources/views/profile.blade.php
<h3>{{ __('profile.content_list', [
    'content_type' => __('content_types.movie', $movies->count()),
]) }}</h3>
<ul class="content_list">
// content list goes here...
                

We see that this now says "Your uploaded videos lives here", which doesn't make any sense. We realise that audio will break as a result of pluralisation and that we haven't even considered how things need to change for other languages. We can't go back to the client and let them know that we're unable to get the job done in time, so we pull the original developer off their other project and ask them to have a think about what needs to be included in the solution.

In summary

We need to be mindful of the fact that a "resource" is not a resource. Software design and development is not about the ability to write code, it's about expertise in solving problems - code happens to be the medium through which individuals are able to solve these problems. We can't expect other developers to jump right in to a project and make changes to it, even seemingly trivial ones like this. Just because a developer is familiar with PHP, or a designer regularly uses Sketch, it doesn't mean that they have the knowledge needed to work on a project anywhere near as efficiently as somebody else. We need to consider an individuals technical abilities, experience and familiarity with a project before assuming that even the most trivial update to a project can be tackled.

In the scenario I've detailed here, it would have been preferable to simply have a conversation with the developer who originally worked on the project, who would have been familiar with the project-specific considerations, and who could have ultimately saved a whole bunch of hassle and stress.