Wednesday, 28 June 2023

The Square and Diagonal Lashing Analogy

Time for this year's ropework analogy!

In my time in the Republic of Singapore Navy, I've come across some truly horrible instructions about how to tie sailor knots, ranging from the misguided to the outright untrue. And some of these involve the Square Lashing and the Diagonal Lashing.

Both of these are knots meant to secure spars, or poles, or bars (indeed, any long roughly cylindrical object), to each other.

Diagonal Lashing: taken from
Art of Manliness.


Square Lashing: taken from
Art of Manliness.

No confusion there. That's straightforward enough. The misconception I often heard going around was that Square Lashings are meant for bars that cross each other on a 90 degree angle, and Diagonal Lashings are for bars that cross each other in a diamond shape.

Well, first off, that's terribly hard to quantify. What's the treshold when one should decide that the angle no longer merits a Square Lashing, and one should go for a Diagonal Lashing instead? 85 degrees? 45? Or, anything even a hair askew from a perfect 90 degree angle?

No, the real qualifier is in the angle of the forces on these two bars. For clarity, refer to the diagrams below. The arrows point to the forces that the knots are supposed to counteract.


The Square Lashing is used to prevent two bars from sliding across each other, as illustrated by the figure on the left.

The Diagonal Lashing is used when the two bars need to be prevented from springing apart, as illustrated by the figure on the right.


Taken from Scout Pioneering.

Above, you can see a sample of the standard trestle. The Square Lashings are used even in places where the bars cross each other at an oblique angle. The Diagonal Lashing is used right in the middle, where the bars have already been secured, and just need to be bound together. The angle has nothing to do with it whatsoever!

The Software Analogy

The above misconceptions occurred largely due to the naming conventions for these two knots. If you call one a Square Lashing and another a Diagonal Lashing, naturally people are going to assume that this has to do with the angle at which these two bars cross.

Similarly, bad naming conventions in programming mislead people who are reading the code. Badly-named methods, objects and variables lead people into misunderstanding their purpose based on a name.

Take the issue of splitting strings into arrays, for example. If you were using JavaScript, Ruby, Python or any number of other programming languages, you would probably use the aptly named split() function or method. In PHP, however, it's named explode() in bizarre fashion.

And how about PHP's function nl2br()? Even disregarding the wonky nature of the acronym aside, it stands for "new line to break", which implies that any string passed into it will have its new lines turned into HTML break tags. But nope, it simply inserts HTML breaks before those new lines instead.

Or, to get off PHP's case for a moment, how about inserting items into collections? In Python, you use the insert() method to add an item into a list. In JavaScript, you use push() to insert into an array. Neither of these will return a new collection!

Conversely, a well-named element can provide instant clarity regarding the intent of the programmer, or if not, at least point the programmer in the right general direction. Hopefully these examples, as well as the ropework analogies given above, will encourage programmers to do the same!

Till next time, be there or be square!
T___T

Thursday, 22 June 2023

An Examination of the CSS Display Property (Part 3/3)

Up next, we examine using the inline-block value for the display property. As far as I can tell, there are no HTML5 elements whose display property is, by default, inline-block. Therefore, this is something that a web developer has to explicitly define in the styling.

One of the most common usages of this is horizontal navigation bars.

display: inline-block

Using this value causes the element to have width, height and padding all definable (and by extension, the float property) while otherwise behaving exactly like an inline element.

Here is a span tag <span style="outline:1px solid red;width:100px;height:100px;padding:5px">with display property unmodified</span> for illustration.
<br />
Here is a span tag <span style="outline:1px solid red;width:100px;height:100px;padding:5px;display:inline-block">with display property inline-block</span> for illustration.


The first span tag behaves exactly as we would expect. The width specified is not long enough, so the span tag expands. But in the second tag, the span tag is an inline-block element, and the width's value is honored. Also, the height's specification works in the latter case but not the former.
Here is a span tag with display property unmodified for illustration.
Here is a span tag with display property inline-block for illustration.


We've tried turning an inline element into an inline-block element. What happens when we do that to a block element?
Here is a p tag <p style="outline:1px solid red;width:100px;height:100px;padding:5px">with display property unmodified</p> for illustration.
<br />
Here is a p tag <p style="outline:1px solid red;width:100px;height:100px;padding:5px;display:inline-block">with display property inline-block</p> for illustration.


In the first instance, the div takes on its own row. In the second example, the div has been changed to an inline-block element and now flows within the content in the same row! In both cases, height and padding reflect the values that have been input.
Here is a p tag

with display property unmodified

for illustration.
Here is a p tag

with display property inline-block

for illustration.


In a nutshell

Use inline elements for cases where you need the content to flow within the content that it appears in.

Use block elements for cases when you need the content to occupy its own row.

And when you need the content to flow and yet also want to control, the width, height, padding (and all associated properties), use inline-block for the display property.

See you again. Don be a stranger!
T___T

Monday, 19 June 2023

An Examination of the CSS Display Property (Part 2/3)

Block elements are responsible for much of the layout in HTML. While inline elements tend to focus more on content, block elements are usually the placeholders that house that content.

The common div tag is a ubiquitous example. So are paragraph and header tags. In fact, many of the tags introduced in HTML5 are block-level elements - footer, aside, article, section and so on. Basically, tags that, before HTML5, might have been represented as div tags.

display: block

One feature of a block element is that they will always start on a new row.

Let's try this with a paragraph.
Here is a <p style="outline:1px solid red;">paragraph tag</p> for illustration.


Here, we see that the content of the tag is on its own line! And it has a top and bottom margin, to boot.
Here is a

paragraph tag

for illustration.


Another feature of block-level elements is that if width is not specified, they take up the entire width of their parents by default.
Here is a <div style="outline:1px solid red;">div tag with no width specified</div> for illustration.
<br />
Here is a <div style="outline:1px solid red;width:50%">div tag with 50% width specified</div> for illustration.


The div tags still take up their own row, but only the first one, with no width specified, takes up the entire row. Unlike the paragraph example above, it has no padding by default.
Here is a
div tag with no width specified
for illustration.
Here is a
div tag with 50% width specified
for illustration.


Now how about height and padding? Let's see...
Here is a div tag <div style="outline:1px solid red;height:50px;width:100px;padding:5px">with a little padding</div> for illustration.
<br />
Here is a div tag <div style="outline:1px solid red;height:50px;width:100px;padding:20px">with more padding</div> for illustration.


The padding works vertically and horizontally, and both width and height are honored!
Here is a div tag
with a little padding
for illustration.
Here is a div tag
with more padding
for illustration.


And of course, since there are widths specified, the float property will work!
<div style="outline:1px solid red;height:50px;width:100px;padding:5px;float:left">Floated left with a little padding.</div>
<div style="outline:1px solid red;height:50px;width:100px;padding:20px;float:right">Floated right with more padding</div>


Floated left with a little padding.
Floated right with more padding



Next

Using inline-block.

Saturday, 17 June 2023

An Examination of the CSS Display Property (Part 1/3)

The CSS property display is one of the pillars of web layout. It has several possible values, but today we will discuss mainly four - none, inline, block and inline-block. We will be going through what all these do.

display: none;


display: inline;


display: block;


display: inline-block;


Just to get it out of the way...

The value none for the display property will cause the element it is applied to, to not even show up in the browser. It will have visually the same effect as if the element (and its contents) did not exist in the HTML at all.

Got that? Good. Let's talk about inline elements. The majority of HTML elements tend to be inline by default, especially formatting tags such as b, i, em and strong. You can also use display: inline to force block level elements to act like inline elements (and vice versa) but this is usually impractical.

display: inline

Inline elements fit neatly on the same line they are introduced. Width-wise, they take up exactly the amount of space needed, no more or less. This also means that any attempts to manipulate the width via the width property will not work.

Here's an example using spans tag. For clarity, I have given it a red outline.
Here is a span tag <span style="outline:1px solid red">with a short string</span> for illustration.
<br />
Here is a span tag <span style="outline:1px solid red">with a much longer string</span> for illustration.


Here, you can see the difference. The span tag with the longer string automatically stretches to fit.
Here is a span tag with a short string for illustration.
Here is a span tag with a much longer string for illustration.


We've seen how inline elements handle width. Now how about height?
Here is a span tag <span style="outline:1px solid red;padding:5px">with a little padding</span> for illustration.
<br />
Here is a span tag <span style="outline:1px solid red;padding:20px">with a more padding</span> for illustration.


Here, we see that the padding affects the width in terms of space taken up, but not the height.
Here is a span tag with a little padding for illustration.
Here is a span tag with a more padding for illustration.


A possible exception for this is img tags. These tags are technically inline, but due to the ability to affect both width and height, they actually perform more like inline-block elements (which we will cover later).

donaldtrump.jpg

Yes, I used a picture of Donald Trump. He may as well make himself useful in this very educational blogpost.
Here is a img tag <img src="donaldtrump.jpg" style="outline:1px solid red;width:100px;height:100px">with more height for illustration.
<br />
Here is a img tag <img src="donaldtrump.jpg" style="outline:1px solid red;width:50px;height:50px">with less height for illustration.


As you can see, the images fall on the same line that they are introduced in, like inline elements. But height and width can be explicitly set, like inline-block elements! The explanation can be found here.
Here is a img tag with more height for illustration.
Here is a img tag with less height for illustration.00


This begs the question: how about floating? Well, since one needs a defined width in order for the float property to work at all, it stands to reason that this would not work for inline elements. Would it work for images, though?

Let's try it...
Here is a img tag <img src="donaldtrump.jpg"style="outline:1px solid red;width:50px;height:50px;float:left">floated left for illustration.
<br />
Here is a img tag <img src="donaldtrump.jpg"style="outline:1px solid red;width:50px;height:50px">with no float for illustration.


It works! img tags are a strange exception to the rule for inline elements, that's for sure.
Here is a img tag floated left for illustration.
Here is a img tag with no float for illustration.


Next

Using block elements.

Sunday, 11 June 2023

Web Tutorial: The PKCE Generator

Security in the web comes in several different forms. If you're engaged in using any kind of web-based API with REST protocol, chances are you would have to deal with authentication protocols such as OAuth. In such cases, a PKCE (Proof Key Certification Exchange) may be required.

Some further reading here.

Suffice to say, you'll need to generate a Code Verifier and use the Code Verifier to generate a Code Challenge. We will use JavaScript for the first part and PHP for the second. We could use PHP for both, but it's better for our purposes to use JavaScript.

What is a Code Verifier?

It's a string that has length between 43 to 128, and only with the characters "-", "_", ".", "~", a to z (and uppercase equivalents) and numbers 0 to 9. As mentioned earlier, we could easily use PHP to generate this code with just one line, but then the purpose of this web tutorial would be largely lost. I want to bring you through the logical process of creating such a string,

So without further ado, here's some bare-bones HTML in a PHP file. Note that there won't be much styling; this code isn't meant to be pretty.
<!DOCTYPE html>
<html>
    <head>
        <title>PKCE Generator</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>

    </body>
</html>


We start with a fieldset tag in the HTML, and a legend. And a form. There's no action attribute specified for the form, because it's just going to call itself.
<!DOCTYPE html>
<html>
    <head>
        <title>PKCE Generator</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>    
        <fieldset>
            <legend>PKCE Generator</legend>
            <form method="POST">

            </form>            
        </fieldset>

    </body>
</html>


In here, I am going to outline the steps needed for the PKCE. Take note of the buttons. The first button is not meant to submit the form, so we have to explicitly specify its type as "button". For the second button, we leave that specification out because it is going to submit the form.
<!DOCTYPE html>
<html>
    <head>
        <title>PKCE Generator</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>   
        <fieldset>
            <legend>PKCE Generator</legend>
            <form method="POST">
                1. Generate a Code Verifier. <button type="button">Generate</button><br />
                <br />        
                <br />
                2. Generate Code Challenge. <button>Generate</button><br />

            </form>            
        </fieldset>
    </body>
</html>


Then we insert two input tags, ids txtVerifier and txtChallenge, respectively. Also make sure they have name attributes as well, because these will be needed when submitting the form. For txtVerifier, the maxlength attribute has been set to 128 just in case the user wants to enter a verifier manually. Both of these input fields have been styled using the CSS class inputlength, which basically sets the width to 100 em.
<!DOCTYPE html>
<html>
    <head>
        <title>PKCE Generator</title>

        <style>
            .inputlength
            {
                width: 100em;
            }

        </style>

        <script>

        </script>
    </head>

    <body>
        <fieldset>
            <legend>PKCE Generator</legend>
            <form method="POST">
                1. Generate a Code Verifier. <button type="button">Generate</button><br />
                <input id="txtVerifier" name="txtVerifier" maxlength="128" class="inputlength" value="" />
                <br />        
                <br />
                2. Generate Code Challenge. <button>Generate</button><br />
                <input class="inputlength" id="txtChallenge" value="" />
            </form>            
        </fieldset>
    </body>
</html>


Now, we add some PHP, declaring verifier and challenge as empty strings. Then we make sure that the value attribute of the input tags have these strings in them.
<!DOCTYPE html>
<html>
    <head>
        <title>PKCE Generator</title>

        <style>
            .inputlength
            {
                width: 100em;
            }
        </style>

        <script>

        </script>
    </head>

    <body>
        <?php
            $verifier="";
            $challenge = "";
        ?>  
 
    
        <fieldset>
            <legend>PKCE Generator</legend>
            <form method="POST">
                1. Generate a Code Verifier. <button type="button">Generate</button><br />
                <input id="txtVerifier" name="txtVerifier" maxlength="128" class="inputlength" value="<?php echo $verifier;?>" />
                <br />        
                <br />
                2. Generate Code Challenge. <button>Generate</button><br />
                <input class="inputlength" id="txtChallenge" value="<?php echo $challenge;?>" />
            </form>            
        </fieldset>
    </body>
</html>


Got all that? Cool. Visually, this is all the change we're going to make here.




Let's start writing JavaScript. We begin with a pkcegen object to properly encapsulate things.
<script>
    let pkcegen = {

    };

</script>


In here, we want a nice useful random number generator that will give us a value between min and max. Nothing much to see here, but if you want more elaboration, check out this previous blogpost!
<script>
    let pkcegen = {
        randomNumber: function(min, max)
        {
            return Math.floor(Math.random() * (max - min)) + min;
        }

    };
</script>


Now, let's create a method to generate a verifier! It will be called genVerifier(). Yes, yes, not very creative. Blow me.
<script>
    let pkcegen = {
        genVerifier: function()
        {

        },

        randomNumber: function(min, max)
        {
            return Math.floor(Math.random() * (max - min)) + min;
        }
    };
</script>


We declare a variable, strLength, which will be the length of the string we are abut to generate. Using the randomNumber() function, we make sure that it's a number between 43 and 128.
genVerifier: function()
{
    var strLength = this.randomNumber(43, 128);
},


Then we declare verifier as an empty string. At the end of this method, verifier will be populated in the textbox txtVerifier.
genVerifier: function()
{
    var strLength = this.randomNumber(43, 128);
    var verifier = "";

    document.getElementById("txtVerifier").value = verifier;

},


Now, we create a For loop to use strLength's value to create the string.
genVerifier: function()
{
    var strLength = this.randomNumber(43, 128);
    var verifier = "";

    for(let i = 0; i < strLength; i++)
    {

    }


    document.getElementById("txtVerifier").value = verifier;
},


We declare currentChar within the loop, then set it to the value returned by calling the genVerifierValidChar() method. And then we concatenate verifier with the value of currentChar.
genVerifier: function()
{
    var strLength = this.randomNumber(43, 128);
    var verifier = "";

    for(let i = 0; i < strLength; i++)
    {
        var currentChar;
        currentChar = this.genVerifierValidChar();

        verifier = verifier + currentChar;

    }

    document.getElementById("txtVerifier").value = verifier;
},


Let's create genVerifierValidChar() next!
genVerifier: function()
{
    var strLength = this.randomNumber(43, 128);
    var verifier = "";

    for(let i = 0; i < strLength; i++)
    {
        var currentChar;
        currentChar = this.genVerifierValidChar();

        verifier = verifier + currentChar;
    }

    document.getElementById("txtVerifier").value = verifier;
},
genVerifierValidChar: function()
{

},

randomNumber: function(min, max)
{
    return Math.floor(Math.random() * (max - min)) + min;
}


We first declare index, and set it to a random number between 0 and 5.
genVerifierValidChar: function()
{
    var index = this.randomNumber(0, 5);
},


Then we use a switch statement on index.
genVerifierValidChar: function()
{
    var index = this.randomNumber(0, 5);
    
    switch(index)
    {

    }

},


So for the first four cases, we return different values. The break statements are redundant since there are return statements preceding them, but I like to leave them there. For the time being, we just return an empty string for the default case.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        return "";
        break;
}


Right now, all we have are these characters.




Now let's comment off the empty string. Instead, as a default, we declare letterIndex as a number between 0 to 3.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        //return "";
        var letterIndex = this.randomNumber(0, 3);
        break;
}


Then we run another switch statement on letterIndex.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        //return "";
        var letterIndex = this.randomNumber(0, 3);
        switch(letterIndex)
        {

        }

        break;
}


For the first case, we use the fromCharCode() method of the String class, passing in a random number from 48 to 57 to give us numbers from the ASCII character set.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        //return "";
        var letterIndex = this.randomNumber(0, 3);
        switch(letterIndex)
        {
            case 0: return String.fromCharCode(this.randomNumber(48, 57)); break;
        }
        break;
}


The second case gives us lowercase letters.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        //return "";
        var letterIndex = this.randomNumber(0, 3);
        switch(letterIndex)
        {
            case 0: return String.fromCharCode(this.randomNumber(48, 57)); break;
            case 1: return String.fromCharCode(this.randomNumber(65, 90)); break;
        }
        break;
}


And by default, we return uppercase letters.
switch(index)
{
    case 0: return "-"; break;
    case 1: return "_"; break;
    case 2: return "~"; break;
    case 3: return "."; break;
    default:
        //return "";
        var letterIndex = this.randomNumber(0, 3);
        switch(letterIndex)
        {
            case 0: return String.fromCharCode(this.randomNumber(48, 57)); break;
            case 1: return String.fromCharCode(this.randomNumber(65, 90)); break;
            default: return String.fromCharCode(this.randomNumber(97, 122)); break;
        }
        break;
}


Click the first Generate button. You'll get a value!




But if there's a little too many special characters for your taste, hey, just adjust this value.
genVerifierValidChar: function()
{
    var index = this.randomNumber(0, 50);

    switch(index)
    {
        case 0: return "-"; break;
        case 1: return "_"; break;
        case 2: return "~"; break;
        case 3: return "."; break;
        default:
            //return "";
            var letterIndex = this.randomNumber(0, 3);
            switch(letterIndex)
            {
                case 0: return String.fromCharCode(this.randomNumber(48, 57)); break;
                case 1: return String.fromCharCode(this.randomNumber(65, 90)); break;
                default: return String.fromCharCode(this.randomNumber(97, 122)); break;
            }
            break;
    }

},


That's it for the Code Verifier...

What is a Code Challenge?

The Code Challenge is the Base64-encoded SHA-256 hash of the Code Verifier. Sounds complicated? Not really, it just means that you have to put the Code Verifier that you can now generate, through a few processes.

So let's write some PHP. If there's POST data, set verifier to the value sent by txtVerifier. You know, the value inside the textbox you just filled by clicking the first Generate button?
<?php
    $verifier="";
    $challenge = "";

    if (sizeof($_POST) > 0)
    {
        $verifier = $_POST["txtVerifier"];            
    }

?>    


Now use the hash() function to get the SHA-256 hash of verifier. Assign the value to the variable hash.
<?php
    $verifier="";
    $challenge = "";

    if (sizeof($_POST) > 0)
    {
        $verifier = $_POST["txtVerifier"];
        $hash = hash("sha256", $verifier);
    }
?>    


We now use the base64_encode() function on hash. However, due to the limitations of PHP, we can't just use it on hash. We need to first put hash through the pack() function. We pass "H*" as the first argument. "H" is for Hex strings and the "*" just means you want to work on the entire string.
<?php
    $verifier="";
    $challenge = "";

    if (sizeof($_POST) > 0)
    {
        $verifier = $_POST["txtVerifier"];
        $hash = hash("sha256", $verifier);
        $challenge = base64_encode(pack("H*", $hash));        
    }
?>    


So far this is what you should get if you generate.




Your output should not contain slashes, the plus sign or the trailing equal sign. So here, we'll use the strtr() function to replaces plusses and slashes with the hyphen and underscore characters respectively, and the rtrim() function to remove the trailing equal signs.
<?php
    $verifier="";
    $challenge = "";

    if (sizeof($_POST) > 0)
    {
        $verifier = $_POST["txtVerifier"];
        $hash = hash("sha256", $verifier);
        $challenge = base64_encode(pack("H*", $hash));
        $challenge = strtr($challenge, "+/", "-_");
        $challenge = rtrim($challenge, "=");

    }
?>    


There you have it.




Challenge accepted,
T___T

Monday, 5 June 2023

Didn't get that promotion? Blame The Peter Principle

Ever heard of The Peter Principle? I might have mentioned it in a previous blogpost, in passing. No matter, you're about to.

In a nutshell, The Peter Principle describes a phenomenon where people are employed to the level of their incompetence. Thus, if someone is doing very well in their current role, they get promoted. If they do very well in that next role, they again get promoted. But if they don't do well, they aren't demoted, but rather stay stuck at the role in which they're not doing so well. Therefore, it follows that most people who are in their current roles are underqualified for them, because if they weren't, they would already have been promoted.

Your profession is not a game

This is relevant because many people have come to me with little nuggets of wisdom such as, the assumption that I should be able to manage other programmers just because I can do the job of programming. Not only is that absolute rubbish with regard to software development, I suspect that this is untrue in many other positions outside of software development where the term "Management" actually comes with the requirement for said Management to, well, manage someone. The skillsets for Management and for doing the grunt work of writing code, are two very different animals.

This is not a scenario where if you kill enough goblins, eventually you will be promoted and start killing dragons. Life is not that straightforward, and the workplace has evolved from factory conditions of yore. No, in this case, you have to develop the skills necessary for dragon-slaying. It's a somewhat wobbly analogy, but I think my point has been made.

How this is seen in the workplace

This is relevant also because I've seen people get resentful and disillusioned over not getting promoted. When there's a vacancy higher up, it's natural for people to expect to be considered. More often than not, what happens is that someone from outside the company gets hired for that position and becomes their superior.

Why do companies do this? Wouldn't it make more sense to promote someone who's already proven themselves at this level? No, it would not, and let me explain why.

Example 1

Here's a hypothetical example. Let's say a position above you opened up. Either you or your colleague are potentially up for promotion. You are the better, more organized, more experienced and more productive worker. Your colleague? Well, she kind of sucks on occasion. But she got the promotion.

Ascending!

Why? Is she prettier than you? Did she kiss ass harder? That's certainly possible.

But the simpler reason was, she represented the safer choice. You're doing well in your current position. The Peter Principle dictates that there is a chance that you might struggle if promoted. On the other hand, your colleague already sucks in her current position. Even if she ends up sucking in her new role, it would still be preferable to you being promoted and both of you sucking at your jobs.

From Management's point of view, promoting your less stellar colleague represents a zero net loss for them, at worst.

Example 2

Here's another example, this time on a larger scale. A Software Project Manager is leaving the company for greener pastures. Now, Upper Management is faced with the age-old question - do they promote one of the existing Senior Software Engineers, or hire someone from outside the company?

Let's assume they go with the first choice. Reward loyalty, right? But then, if they promote that Senior Software Engineer, that leaves another vacuum to be filled. Do they just redistribute that workload among the other Senior Software Engineers? Bad idea. How about promoting a Mid-senior Software Engineer to the title (and the perks, and workload) of a Senior Software Engineer? And if that also leaves a vacuum, perhaps more promotions?

It's all well and good so far, assuming that all these recently-promoted people have no problems in their new role. But as we all know, that rarely happens. There are always teething issues, and in the worst-case scenario, the newly-promoted Software Project Manager is terrible. He or she simply isn't cut out for it despite being an excellent Senior Software Engineer. If you find yourself a bit too surprised by that, then you obviously don't understand software development very well.

But hang on - that's not actually the worst-case scenario. The worst that can happen is that all of the newly-promoted people suck in their new roles, all at the same time. Whereas before promotion, they were flourishing! So, from a Management standpoint, why would you screw that up? Why would you promote a bunch of people into new roles and pay them more, just for them to potentially struggle?

There can be only one.

But what if they just hired someone from outside the company, into the newly-vacated role? Well, there's only been one promotion and therefore only one possible point of failure!

That's the logic anyway. Real life is rarely that cut and dry.

The takeaway

Nothing I've said here today is hyperbole. The Peter Principle is real.

When you don't get that promotion, it probably has nothing to do with you. In fact, the better you are at what you do, the more indispensable you make yourself at your position, and consequently, the harder it is to promote you.

Signing off in principled fashion,
T___T