Saturday 30 March 2024

Spaghetti, waffles, and their relevance to tech work

Recently, I read a book review about the differences between men and women. Don't ask me how that came to my attention, it's hardly the kind of stuff that I take an active interest in. In summary, the article claims that men's brains are like waffles and women's like spaghetti.

Spaghetti and waffles!

In essence, men tend to compartmentalize. Men tend to be focused. Each activity takes place in a space of its own - much like the squares on a waffle. There is little no no overlap. When a man is working, he's working. When a man is watching football, he's watching football.

Women, on the other hand, tend not to compartmentalize. Everything is interconnected. Everything affects everything else. This, of course, would be a neat explanation for why my wife somehow manages to talk about me spending too much money on insurance policies when I'm trying to talk about the correct way to brew chrysanthemum tea.

Or at least, it would be, if I bought this theory.

How this would play in tech

Is this accurate? Well, who knows for sure?

The more important question would be - what if it was? You see, in tech, there's a popular theory (which is way more popular than I feel it should be) that men are better suited to tech because they're more focused and logical, whereas women are more intuitive and emotional. And some women I know have even bought into this theory, claiming rubbish like "I'm a woman. I'm supposed to be emotional."

Look, I acknowledge that the following is merely an assumption on my part. Maybe not everyone gets out as much as they should. But most of us would know men who are sensitive and emotional, and women who are cold, clinical and rational. They may not be the majority of men and women, but they do exist. And they are no less men and women for that. At least, not in my eyes.

So let's say that this theory is true, and that men are generally more focused and prone to compartmentalization. Would that make them better programmers? Maybe. After all, a large part of programming is writing objects and methods, and what are the best methods? The ones that accomplish a single goal, no more. The ones that are largely separate from other methods. Loosely coupled. But would that mean men are better suited to tech? Only if you think software development is nothing but programming. And, if you have any substantial amount of experience in that area at all, you would recognize how laughable an idea that is.

More than writing code.

Tech also needs architects and system analysts. People who see the bigger picture, and can accurately point out how one area of the system potentially affects another. And who better for that, than the stereotypical woman? So if men are better coders and women are better system architects, wouldn't it stand to reason that both men and women are just as suited to tech, but perhaps in different roles?

Food for thought! Literally!

Again, the above supposes that I agree with the assertion that men are like waffles and women are like spaghetti.

I don't. I think human beings come with a staggering array of personality types, and it's these personality types that we need to look out for when determining suitability for a tech job.I think tech would be better served if we were to classify people based on their problem-solving approaches, rather than by their gender.

Quit waffling around!
T___T

Tuesday 26 March 2024

Separating Text Editors from IDEs

The acronym "IDE" stands for Integrated Development Environment. There is a little bit of confusion as to what IDEs are, leading to questions like "Is TextPad an IDE?" (Spoiler: The answer is No).

TextPad is a text editor. There are distinct differences between a text editor and an IDE, even though they may look similar to a layperson. Chief of which, a text editor is part of an IDE. An IDE comprises of many components, one of which is a code editor of some sort.

What Text Editors do

Text editors edit text. It could be a block of code, a poem about dinosaurs or a dissertation about why dolphins are such jerks. Think of your text editor as a drum. The thing you beat with a stick so it makes sounds? Yeah, I know, that sounds wrong. But anyway...

Now a text editor isn't exactly a code editor, but it's awfully close. A code editor edits code, which is basically text. It's essentially a specialized kind of text editor, highlighting code structures and syntax errors, autocomplete suggestions and maybe even beautifying it for human eyes.

Now if you think of your text editor as a drum, think of your code editor as a full drum set with cymbals.

Full drum set.

Technically, not all code is text, but for most high-level programming languages, they are. Sublime Text, for example, can edit code for PHP, HTML, Python and a host of other languages. Notepad will edit the text just fine, but won't highlight syntax. That's pretty much the difference between editing code and editing text. Most text editors can edit code in a pinch, and vice versa.

As a web developer, I've had to use text editors to edit HTML, JavaScript and CSS code. And generally didn't encounter many problems. You could still do that for code that needs to be compiled, such as Java or C#, but that would make the process of development way harder than it needs to be.

What IDEs do

IDEs consolidate common developer tools onto one interface, so this potentially eliminates the need to individually configure separate software packages. At the very least, an IDE provides a code editor and an environment for running the code.

Now if following the earlier analogies, think of your IDE as a rock band setup with drums, keyboard, bass guitar and drum set, all in one place!

A full rock band setup.

Some IDEs provide other features, such as:
- file versioning.
- deployment management for DevOps.
- workflow and project management features.
- build automation
- specialized interfaces for mobile development, such as Android Studio.

An example of an IDE would be Eclipse (for Java and Python, among others) and Visual Studio (which handles C#, HTML and so on). They are called IDEs because they also run the code in addition to editing it. They can debug the code and point out syntax and (some) logical errors.

In a Nutshell

Text editors basically process and format text. IDEs almost always include a text editor of some sort, but the function of an IDE goes beyond text editing.

Text you later,
T___T

Saturday 23 March 2024

Web Tutorial: Bus Arrival App

Good day in sunny Singapore!

Today we will embark on a little project I kept shelving for the past couple years - the Bus Arrival app! It's not a new concept by any means - there are already plenty of apps out there that do the exact same thing... but hey, why use someone else's app and put up with their crappy ads when you can just make your own, eh?

Bus Stop Code.

So here's a bit of context. This is Singapore, and every bus stop has a number. Some bus stops have this nifty feature where they show you how many minutes it will take for your bus to arrive at the stop. But not every stop has it, and thus we use an app to check. Singapore's Land Transport Authority released their API back in 2011, and we will leverage upon this data. Before we begin, you will need to register for an API key.

What's going to happen after this, is that we write some HTML code that will display the results, and some PHP code to grab the results.

Let's kick this off!

Here's some HTML code. Bear in mind thiis code is not meant to be pretty. If you want pretty, manage your own aesthetics. The body is basically set to a white background and a bit of font styling in the CSS, for now. In the body, there is a div with id container that houses two other divs - stop and bus.
<!DOCTYPE html>
<html>
    <head>
        <title>Singapore Bus Arrival</title>

        <style>
            body
            {
                background-color: rgb(255, 255, 255);
                font-family: sans-serif;
                font-size: 16px;
            }
        </style>

        <script>

        </script>
    </head>

    <body>
        <div id="container">
            <div id="stop">

            </div>

            <br/>

            <div id="bus">

            </div>

            <br/>
        </div>
    </body>
</html>


In the stop div, we add a header tag and an emoji.
<div id="stop">
    <h1>&#128655; BUS STOP</h1>
</div>


Then we have a form.
<div id="stop">
    <h1>&#128655; BUS STOP</h1>
    <form method="POST">
    
    </form>

</div>


In there, we have an input field that will accept only numbers. We manage this by setting the type attribute to number. For its name attribute, we use txtStop.
<div id="stop">
    <h1>&#128655; BUS STOP</h1>
    <form method="POST">
        <input type="number" name="txtStop" placeholder="e.g, 9810007" />
        <button name="btnFindStop">FIND THIS STOP</button>

    </form>
</div>


Bare bones look... it'll get better.



The second div, bus, now should also have a header tag with an emoji.
<div id="bus">
    <h1>&#128652; BUS SERVICES</h1>
</div>


Let's style all this a little. container will have rounded corners and a translucent brown border, and we give it some generous padding.
body
{
    background-color: rgb(255, 255, 255);
    font-family: sans-serif;
    font-size: 16px;
}

#container
{
    border-radius: 20px;
    border: 3px solid rgba(100, 0, 0, 0.8);
    padding: 2em;
}


The divs within container will also boast round corners with translucent brown borders, a less generous padding, and black text.
#container
{
    border-radius: 20px;
    border: 3px solid rgba(100, 0, 0, 0.8);
    padding: 2em;
}

#container div
{
    border-radius: 20px;
    border: 3px solid rgba(100, 0, 0, 0.2);
    padding: 0.5em;
    color: rgb(0, 0, 0);
}


And then we have stylings for the form inputs as well, but all this is really aesthetics and should make very little difference to functionality. Do as you will.
#container div
{
    border-radius: 20px;
    border: 3px solid rgba(100, 0, 0, 0.2);
    padding: 0.5em;
    color: rgb(0, 0, 0);
}

#stop input
{
    border-radius: 5px;
    padding: 5px;
    width: 10em;
    height: 1em;
}

#stop button
{
    background-color: rgb(50, 0, 0);
    color: rgb(255, 255, 255);
    border-radius: 5px;
    padding: 5px;
    width: 10em;
}

#stop button:hover
{
    background-color: rgb(50, 50, 0);
}


This is what it looks like so far.



Now, we will make the form work, using some PHP code. We start by declaring buses as an empty array, and busStop as an empty string.
<?php
    $buses = [];
    $busStop = "";
?>


<!DOCTYPE html>
<html>


The rest of the code should only work if the form has been submitted. Thus, we use an If block to use the isset() function and check if there exists a POST variable called btnFindStop, which is the name of the button in the form.
<?php
    $buses = [];
    $busStop = "";

    if (isset($_POST["btnFindStop"]))
    {

    }

?>

<!DOCTYPE html>
<html>


We set the value of busStop to the POSTed value of txtStop. Then we prepare to use cURL by running the curl_init() function, and assigning the result to the object curl.
if (isset($_POST["btnFindStop"]))
{
    $busStop = $_POST["txtStop"];
    $curl = curl_init();

}


We next run the curl_setopt_array() function, passing in the curl object as the first argument...
if (isset($_POST["btnFindStop"]))
{
    $busStop = $_POST["txtStop"];
    $curl = curl_init();
    
    curl_setopt_array(
        $curl,
    );

}


... and an entire array of options as the next argument. Note here that this is a GET request, and the URL has been set to the DataMall endpoint, with the BusStopCode parameter value being busStop.
if (isset($_POST["btnFindStop"]))
{
    $busStop = $_POST["txtStop"];
    $curl = curl_init();
    
    curl_setopt_array(
        $curl,
        [
            CURLOPT_URL => "http://datamall2.mytransport.sg/ltaodataservice/BusArrivalv2?BusStopCode=" . $busStop,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_POSTFIELDS => "",

        ]
    );
}


We'll also need to pass in the API key like this. Replace "xxx" with the value of your own key. The content-type property is JSON, and that's what we will parse the result as.
if (isset($_POST["btnFindStop"]))
{
    $busStop = $_POST["txtStop"];
    $curl = curl_init();
    
    curl_setopt_array(
        $curl,
        [
            CURLOPT_URL => "http://datamall2.mytransport.sg/ltaodataservice/BusArrivalv2?BusStopCode=" . $busStop,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_POSTFIELDS => "",
            CURLOPT_HTTPHEADER =>
            [
                "Content-Type: application/json",
                "accountKey: xxx"
            ],

        ]
    );
}


Run the request using curl_exec() with curl as the argument, and assign the returned value to response. Make a provision for errors as well, using curl_error(), and assigning the returned value to err. Then, as a matter of neatness, use curl_close() on curl.
if (isset($_POST["btnFindStop"]))
{
    $busStop = $_POST["txtStop"];
    $curl = curl_init();
    
    curl_setopt_array(
        $curl,
        [
            CURLOPT_URL => "http://datamall2.mytransport.sg/ltaodataservice/BusArrivalv2?BusStopCode=" . $busStop,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_POSTFIELDS => "",
            CURLOPT_HTTPHEADER =>
            [
                "Content-Type: application/json",
                "accountKey: xx"
            ],
        ]
    );
    
    $response = curl_exec($curl);
    $err = curl_error($curl);
    
    curl_close($curl);

}


If err exists, then there is an error and we want to display it on screen. If not...
$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err)
{
    echo "cURL Error #:" . $err;
}
else
{

}


...declare obj and set its value by running json_decode() with response as an argument. Because response will be in a JSON string. Remember buses, the array? Well, buses will be the Services array within obj.
if ($err)
{
    echo "cURL Error #:" . $err;
}
else
{
    $obj = json_decode($response);
    $buses = $obj->Services;

}


Nothing's going to happen yet. Not until we make a few changes to the HTML. We want busStop to be reflected in the display. Thus, if no bus stop has been searched for yet, the number just isn't going to show.
<div id="stop">
    <h1>&#128655; BUS STOP <?php echo $busStop;?></h1>
    <form method="POST">
        <input type="number" name="txtStop" placeholder="e.g, 9810007" />
        <button name="btnFindStop">FIND THIS STOP</button>
    </form>
</div>


For the bus div, set it to not display if the length of buses is 0.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128652; BUS SERVICES</h1>
</div>


Then use a Foreach loop to iterate through buses.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128652; BUS SERVICES</h1>
    <?php
        foreach($buses as $bus)
        {
    ?>
        
    <?php        
        }
    ?>

</div>


In here, you want a button to appear for each bus service. Display the ServiceNo property of each element in each button. Thus, each bus service will have its own button, labelled.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128652; BUS SERVICES</h1>
    <?php
        foreach($buses as $bus)
        {
    ?>
        <button>
            <?php
                echo $bus->ServiceNo;
            ?>
        </button> 
       
    <?php        
        }
    ?>
</div>


Let's style this a bit. I'll have each button brown with a translucent black border and white text. All up to you; ultimately the functionality is not affected one way or another.
#stop button:hover
{
    background-color: rgb(50, 50, 0);
}

#bus button
{
    background-color: rgb(50, 0, 0);
    color: rgb(255, 255, 255);
    border-radius: 5px;
    border: 3px solid rgba(0, 0, 0, 0.5);
    padding: 5px;
    width: 5em;
    font-size: 20px;
    font-weight: bold;
}    


Now try searching for a nonsense number. Try, "00000". No buses should appear.



But what if you searched for something that actually exists, such as "11111"? You'll see services 153, 165, 174, 186, 48, 855, 93 and 961!



Next we will add more divs after the bus div. Again, iterate through buses using a Foreach loop. In the loop, have a div with a CSS class of arrival.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128652; BUS SERVICES</h1>
    <?php
        foreach($buses as $bus)
        {
    ?>
        <button>
            <?php
                echo $bus->ServiceNo;
            ?>
        </button>        
    <?php        
        }
    ?>
</div>

<br />    

<?php
    foreach($buses as $bus)
    {
?>
    <div class="arrival">

    </div>
<?php            
    }

?>


Inside each div, you should have another emoji with the bus service number.
<?php
    foreach($buses as $bus)
    {
?>
    <div class="arrival">
        <h1>&#128336; BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>

    </div>
<?php            
    }
?>


If the NextBus object of the current element exists, display its EstimatedArrival property.
<?php
    foreach($buses as $bus)
    {
?>
    <div class="arrival">
        <h1>&#128336; BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>
<?php
        if ($bus->NextBus)
        {
            echo "<h2>" . $bus->NextBus->EstimatedArrival . "</h2>";
        }
?>

    </div>
<?php            
    }
?>


Do the same for NextBus2 and NextBus3.
<?php
    if ($bus->NextBus)
    {
        echo "<h2>" . $bus->NextBus->EstimatedArrival . "</h2>";
    }

    if ($bus->NextBus2)
    {
        echo "<h2>" . $bus->NextBus2->EstimatedArrival . "</h2>";
    }

    if ($bus->NextBus3)
    {
        echo "<h2>" . $bus->NextBus3->EstimatedArrival . "</h2>";
    }

?>


Let's see how this looks. You should see 8 new duvs appear, each one bearing a few bus arrival timings!



Unfortunately, these timings are not quite human-friendly. Let's fix that. Use the formatArrivalTime() function on these values.
<?php
    if ($bus->NextBus)
    {
        echo "<h2>" . formatArrivalTime($bus->NextBus->EstimatedArrival) . "</h2>";
    }

    if ($bus->NextBus2)
    {
        echo "<h2>" . formatArrivalTime($bus->NextBus2->EstimatedArrival) . "</h2>";
    }

    if ($bus->NextBus3)
    {
        echo "<h2>" . formatArrivalTime($bus->NextBus3->EstimatedArrival) . "</h2>";
    }
?>


Now at the top of the PHP file, create this function. It has a parameter, strTime.
        else
        {
            $obj = json_decode($response);
            $buses = $obj->Services;
        }
    }

    function formatArrivalTime($strTime)
    {

    }

?>


Define newStr, and use it to store the value of strTime which has the "+8:00" removed using the str_replace() function. Use the str_replace() function on newStr next, this time to replace the "T" with a space.
function formatArrivalTime($strTime)
{
    $newStr = str_replace("+08:00", "", $strTime);
    $newStr = str_replace("T", " ", $newStr);

}


Then use the date() function to return only the time. For this, you'll also need to convert newStr to a time object using the strtotime() function. Here's some reference on PHP datetime functions.
function formatArrivalTime($strTime)
{
    $newStr = str_replace("+08:00", "", $strTime);
    $newStr = str_replace("T", " ", $newStr);
    return date("h:i A", strtotime($newStr));
}


Try it!



Next, we don't want to show all the data at one go. It's a lot of scrolling potentially, and that is murder on a small screen. So do this, to hide the div by default.
<div class="arrival" style="display:none">
    <h1>&#128336; BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>


And then give each div a unique id based on the bus service number.
<div id="arrival_<?php echo $bus->ServiceNo; ?>" class="arrival" style="display:none">
    <h1>&#128336; BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>


For the bus div, each button should run the JavaScript function showArrivalFor(), with the service number passed in as an argument.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128652; BUS SERVICES</h1>
    <?php
        foreach($buses as $bus)
        {
    ?>
        <button onclick="showArrivalFor('<?php echo $bus->ServiceNo; ?>');">
            <?php
                echo $bus->ServiceNo;
            ?>
        </button>        
    <?php        
        }
    ?>
</div>


That function does not exist yet; we will create it.
<script>
    function showArrivalFor($bus)
    {

    }

</script>


We begin by declaring hide as an array of all divs styled using CSS class arrival. (Bet you were wondering if we were ever going to use that, eh?)
<script>
    function showArrivalFor(bus)
    {
        var hide = document.getElementsByClassName("arrival");
    }
</script>


Then we use a For loop to set all of their display properties to none.
<script>
    function showArrivalFor(bus)
    {
        var hide = document.getElementsByClassName("arrival");

        for (var i = 0; i < hide.length; i++)
        {
            hide[i].style.display = "none";
        }

    }
</script>


Finally, just grab the div that has the info you do want to show, using the value of bus. And set its display property to block.
<script>
    function showArrivalFor(bus)
    {
        var hide = document.getElementsByClassName("arrival");

        for (var i = 0; i < hide.length; i++)
        {
            hide[i].style.display = "none";
        }

        var show = document.getElementById("arrival_" + bus);
        show.style.display = "block";

    }
</script>


There should be no arrival timings when you refresh. But if you click on 48, Bus Service 48's srriving timings show.



If you click on 165, then only Bus Service 165's arrival timings show!


And that, geeks of all ages, is how you make a Singapore Bus Arrival app.

This code drives me wild (heh heh),
T___T

Monday 18 March 2024

Profanity-laced Content Over The Years

Long-time readers of this blog will have noticed that whenever certain impolite words are used in a blogpost, I take care to tag the post with the term "Profanity Alert". I've been called many things (and some of them are even true) but let it never be said that I am not in the habit of giving fair warning.

Through the years, the suspicion that I use entirely too many vulgarities to communicate my thoughts, has been entertained, and I have striven to do better, especially where this blog is concerned. It's not a moral issue for me, more a professional one. And perhaps a desire to challenge myself by expressing ideas in a less vitriolic manner.

Wash your mouth!

Thus, imagine my chagrin when I ran some data analytics on tag usage on this blog, and found that "Profanity Alert" was the frontrunner in terms of appearances.

What. The. Fuck?! (Yes I know, this doesn't help my case at all)

The findings

In 2015, things weren't so bad. I was mostly in techie mode. In fact, The tag "Profanity Alert" was not even in the Top 5. I was all business.


Things changed in 2016. "Profanity Alert" was not only in the Top 5, it was numero uno. At this point, I should have suspected a dangerous trend there.


It didn't get better the following year. "Profanity Alert" was still the most frequently used tag. Tags like "Web Development" came a close second. And honestly, it wasn't even that close.


There was a little improvement in 2018. The tag was still in top position, but it was tied with "Web Development". Which I guess meant that I was at least spending as much time talking about things that really mattered, without swearing.


2019 continued in the same vein. "Profanity Alert" and "Life as an Economic Digit" were tied in first place, with "Web Development" running close behind.


2020 was almost a copy of 2019, as far as the top few were concerned. "War Stories" took the place of "Life as an Economic Digit". Now "Web Development" was nowhere to be seen in the Top 10, and "Singapore" was the runner-up in terms of frequency. It marked a change to me talking more about local affairs.


It was in 2021 where I made a concerted effort to stop swearing excessively. To my pleasant surprise, "Profanity Alert" no longer appeared in the Top 10 after having been a mainstay for years. Go, me!


It did not last, alas; for in 2022, "Profanity Alert" slithered back to Numero Uno spot. Imagine my consternation! Bad habits, do, indeed die hard. It was time to stop being complacent.


2023 looked OK, as I made another effort to limit my swearing. It met with some success, for now my posts centered around Social Media. Thank you Elon Musk and Mark Zuckerberg, for giving me so much material to focus on!


2024 has gotten off to a promising start thus far. I have not used enough profanities in any posts to push the "Profanity Alert" tag to prominence. A little discipline seems to have done the trick.




Moving forward

I hope to continue making progress. While in principle, I have nothing against swearing, I think overuse of it ultimately detracts from what this is supposed to be - a tech blog. There are certainly better ways than constantly dropping F-bombs.

Friends Ultimately Choose Kindness!
T___T

Thursday 14 March 2024

That strange feeling that comes with achieving that prize

It's an odd sensation. Early this year, I received another salary increment, which put my pay bracket - and subsequently, my total monthly income - at three times what it had been back in 2012. And it is strange because back then, I was a struggling web developer who was regularly pulling twelve-hour workdays dreaming of one day making a certain amount of money every month. And what was that lofty goal, one might ask? Why, that amount I was aspiring to, is less than half what I make now. Significantly less.

In other words, I'm making more than I ever wanted to.

Was it inflation? No. I did the math. Even with inflation, I'm still making substantially more.

Sure, I make a lot less than many people who are younger than me. But given the fact that I spend like I'm still on that miserable monthly wage twelve years ago, I can feel a hell of a lot more secure than the average millennial.

How?

Spending within your means is merely one way of saving money. Any financial advisor worth their salt will be the first to tell you that saving money isn't the way to increasing your income. It's just a way to minimize your chances of becoming desperately poor. Of ensuring that you always have something in reserve. But it will not make you rich.

It's not working hard and education, either. Sure, I did both. But neither of them, on their own, or even in tandem, got me money. No, it was keeping one eye open for the next opportunity and ruthlessly moving on for a significant pay bump. I always (well, mostly) enjoyed my work, but made sure never to get too comfortable. My first disastrous six-year stint as a desktop support guy taught me that much.

And that brings us back to the issue of always having something in reserve. Living a very financially sustainable lifestyle is what gave me the freedom to just move on whenever I felt like it. No waiting for bonuses or bullshit like that. No, when the TeochewThunder Train moves, it moves.

The train moves on.

Living like you're on your last dollar isn't a lot of fun. Let me tell you what is even less fun - actually being on your last dollar. Living from paycheck to paycheck. Relying on the goodwill of friends and relatives. Taking handouts from the Singapore Government. Relinquishing your last shred of dignity to survive another month. Thankfully I've never had to go that far, partly because I never allowed myself to.

I lived as though I was on my last dollar for years out of necessity, then I started living like this so that I would never again need to live like this.

I mean, what is money really for? Overseas vacations, fancy restaurants, the trappings of the high life? Rubbish. Those are irrelevant. What money ultimately really gets you is freedom. Freedom to do whatever you want, on your own time. I want money so that I don't need to worry about not having any.

That's all it is. That's all it ever was.

And now...

I work a lot less. Partly because with experience, I can recognize lost causes and dial back accordingly. I can get more done with less effort.

And partly because at this point, I have very little left to prove. I'm 47. In ten years, I'm either dead, retired, or well on my way there. If not sooner. I have no kids, or even pets. Being recognized as a valuable member of the company does nothing for me psychologically or emotionally. I lived, I will die, and in my time here I did nothing that would shake the world, or echo through the centuries to come. I am no better than the average schmuck, and I'm perfectly OK with that.

I lived, and I will die.

And also because I've built up a respectable nest egg... and unless I lose it all through a random act of stupidity, I'm good. Thus, I'm not afraid of losing my job or anything like that. I can work without that millstone hanging around my neck. I can actually enjoy my work. It can't be overstated how important that is.

Final Notes

I've been seeing Singapore Parliamentary debates about how ineffectual the WSQ framework is with regard to improving employment. People have been complaining about not being able to get good jobs despite upskilling and upgrading. That's because it's not meant to work that way. The Good Jobs Genie isn't going to suddenly appear and let you have your pick of jobs just because you got a certification in whatever. Upgrading is not a silver bullet that will solve all your problems. It's just one step in a series of many steps, some meant to be taken concurrently.

You owe the world nothing, and in turn, it owes you nothing. Whatever you have is what you can get, and more importantly, what you can keep.



$ee you later!
T___T

Sunday 10 March 2024

Ten Professional Hazards Of Writing Code For A Living

Human beings are creatures of habit. Any profession which entails long sustained periods of doing things or thinking a certain way, will have an influence on its practitioners. Years of being a programmer have changed me. In all fairness, some of these traits already existed way before I wrote my first Hello World program, though they were certainly magnified after that.

Here are some of the ways my job as a software developer have shaped me as a person. Some of these may make me look like an utter moron. I assure you that I am of at least average intelligence. It's just the job.

1. Counting from zero

Probably the most stereotypical quirk ever. "Programmers tend to count from zero". Yeah, right. The stereotype exists because in almost all programming languages, counting does begin from zero.

Do I count from zero? No, that's silly. I don't, for instance, look at a cluster of five apples and tell you there are four. Any programmers who do, I suspect, are just trying too hard for geek cred.

There are five apples, not four.

However, it does happen if I'm looking at rows of data. If I see an MS Excel worksheet with data all the way to number 100, I am going to think there are 101 rows of data. It could be because spreadsheets are usually the way I visualize arrays in my head (especially two-dimensional arrays) so my brain subconsciously thinks of spreadsheets as arrays.

Thus, while this stereotype is way overblown, there's some truth to it.

2. Being easily startled

When deep in the throes of writing code, programmers tend to concentrate really hard. I am no exception. There have been plenty of times when my brain is on a one-track highway through some programming logic when someone interrupts me by speaking in my ear or tapping me on the shoulder.

Violently startled.

And sometimes, my reaction can be... absurdly violent. Spilled coffee, sudden jumps, things like that.

This doesn't happen all that much these days. For one, I work from home. Very few people get to interrupt me. And even if they do, the fact is, I simply don't concentrate as hard as I used to.

3. Being very literal

One of the hallmarks of writing code is being drawn into the true or false dichotomy. Thus, there's this tendency to interpret everything as a "yes" or "no" question. To be fair, sometimes the question is literally phrased this way. But that's only as a manner of speaking; often, the asker means to ask a bigger question.

No capacity for nuance.

And because of this tendency, I tend to miss it.

I remember being at an interview where the hiring manager asked me if I knew how the PayPal IPN works. To me, the answer was obvious. Yes, I do. It was only after an awkward pause, and the interviewer rephrased his question, that I understood that he actually expected me to demonstrate how it works.

There were other interviews where I was asked similar questions where I simply said "Yes" or "No". But honestly, I also feel that if you're going to ask a programmer questions like that, you should also be prepared for replies like that.

4. Single-mindedness

This next one does not apply to all techs or even all programmers. But there's a fair number of programmers who tend to take a very insular view when writing code. This can be useful when you're writing a single-use method; as small as possible. Not so much if you're trying to design an entire system.

Laser focus... or just
tunnel vision.

And in real life, that can have negative consequences too. I've gotten into trouble with the wife for doing the correct thing... at the wrong time, or under the wrong conditions. Because the correct thing, in isolation, is the correct thing. But few things in life exist in isolation.

You don't want to wash the windows when it's raining. Or flush the toilet before taking a piss. All this is putting the cart before the horse, which can happen when you consider only the task at hand and fail to take the larger context into account.

5. Overusing techspeak

Tech work comes with a whole lot of terminology, some of which we're sometimes guilty of assuming that non-techies understand. After all, techspeak has become increasingly mainstream over the last decade as technology has become more entrenched with the general public.

This does not automatically mean that everyone knows what SSL is (despite a staggering majority of websites employing it). Or that a gateway doesn't always mean that entrance to a building enclosure. Or that when we refer to something as a "string literal", we actually just (kind of) mean "text".

No, not that kind of string.

And yes, I'm just as guilty as other tech geeks.

We're not trying to sound smart when we break out the tech jargon, cross my heart. Mostly because we are smart, and know it. No, it's largely because our work practically demands that we speak in what could almost be a different language.

6. Expecting output

As mentioned before, I tend to interpret things very literally. However, this also applies in reverse.

As a consequence of writing functions which expect very specific data type values in a very specific order, as input, and produce output which is also of a very specific data type, what happens is that this has a tendency to manifest when I ask questions of other people: I tend to expect a certain output and only that output. And when I ask for A, and people give me B, C and D in addition to A, I tend to get annoyed.

A lot of irrelevant information.

It's human nature; people want to be helpful. But what usually ends up happening is that they give you a lot of information that has nothing to do with what you wanted in the first place.

7. Cynical

Expecting the worst, or not believing it when things go well, is something ingrained in developers who do a lot of testing, which, let's face it, is pretty much all devs at this point.

Does your code ever run perfectly the first time? And when it did, were you happy or wary?

Glass is always half-empty.

Unless it's something really simple that would have been expected to go right, sometimes when things go too smoothly, I get worried.

My time running code has taught me that when no warnings or errors are reported, it's rarely because I did everything right, especially if it's the first run. No, there are probably bugs and gotchas, and they're well-hidden!

8. The How 

One more quirk of being a web developer is that one of the first questions we tend to ask is the How question. It's a professional hazard that may be shared by engineers in general.

Even when I'm asking something like "why did I get an error 500 on this API endpoint call?" it usually gets formattered as "how the hell did I get an error 500 on this API endpoint call?"

Examining how things work.

That's relevant, I promise. Because even in my early days as a web developer, I was curious about how things worked. I would find stuff on the web, wonder how it was done, and then I would make my own, just to prove I could. This also applies to other things in my life, non-tech related. I'd look at something, figure out the how, and make my own. I'm not sure if I'm this way because I was a web dev, or I became a web dev because I'm this way.

9. Lack of sympathy

I've been accused of having a less than exemplary bedside manner when people complain about their shitty careers or lack of opportunities in the job market. I've also been less than impressed with people who claim to envy the fact that I work in tech.

Heart of stone.

Really? Do people want to potentially spend days sifting through code, making changes that may end up creating problems bigger than the one they're trying to solve? Would they enjoy having to constantly remind their less tech-savvy colleagues that software development is not witchcraft and still has to conform to logic? Do they want to go through the slog I did, in order to get where I am now?

I know I don't. I simply happen to enjoy writing code enough to not overly mind that rest of the bullshit I have to put up with. People want the perceived better pay and job security of tech, but the job itself would drive them nuts.

And I have no sympathy precisely because I know I'm not better than the average schmuck. In the sense that, the moment I'm of no use, I'll be put out to pasture like anyone else. Look at the mass layoffs happening in Big Tech if you're not convinced. Job security? What a joke, right?

10. Flowcharting

Agile practices include making use of a Kanban Board system. The use of said system is good for training an organized mind, and lends into the software development practice of breaking up a huge problem into smaller, more manageable tasks.

The good old
divide-and-conquer.

And this has translated over to my daily life, to things like chores and personal projects. Even long-term goals like language learning. Everything is obsessively broken up into smaller sub-components, then managed.

The wife thinks I'm certifiably insane. She doesn't understand why mopping the kitchen floor and mopping the living room floor are two separate tasks, and have to be scheduled. Honey, I'm just a software dev. It's who I am.

What a hazardous list!

Are you a programmer by trade, and if so, how many of these apply to you?

How many apples do you see?
T___T

Tuesday 5 March 2024

Film Review: Black Mirror Series Four, Redux (Part 3/3)

Next one is a fun one... Black Museum.

The Premise

The titular Black Museum is a place where tech arctifacts and the horror stories that come with them, are displayed. Rolo Haynes is the proprietor, and he narrates some of these stories with a shocking twist at the end. Think of this episode as an episode of mini-episodes.

The Characters

Douglas Hodge is the narrator and antagonist Rolo Haynes. Where do I begin? This guy knocked it out of the park as the loathesome opportunistic sleazebag Haynes, what with the griping about human rights and off-color commentary. Can't give him all the credit, of course, the writing played a big part, but he carried it so well.

Leticia Wright as Nish. Wright recently played Shuri in Black Panther and Wakanda Forever. Here, she plays much the same character - plucky, snarky, good with tech. However, she also adds a more emotional bent to her character, and she's great to watch in the final quarter of the episode.

Daniel Lapaine as Dawson. Guy starts out as a well-meaning doctor who falls prey to the unintended side effects of tech. The actor did a pretty believable job of portraying, with his limited screen time, a healer-turned-psycho. Can I just say the actor's name is oddly apt? Lapaine. Heh heh.


This shot of him lying in a coma with a hard-on just seems very representative of what Black Mirror is as a whole - technology that is touted to improve our lives, turns out to have nasty side effects due to human beings being flawed and using it in terrible ways..

Emily Vere Nicoll as Dawson's concerned and long-suffering girlfriend, Madge. She really doesn't have much to do except look concerned, look repulsed and appear naked. I'm kind of sorry for the actress, to be honest.

Aldis Hodge plays Jack, the single father who faithfully raises his kid after the death of the kid's mother. He does come across as a man admirable in his consistency towards Carrie.


However, there's a limit to how much he can sacrifice and Black Mirror has a way of finding that limit. In particular, having Carrie's consciousness uploaded to his brain, where he has to hear her constantly, and lose his privacy twenty-four seven.

Alexandra Roach delivers a compellingly tragic performance as Carrie Lamasse. This one gave me mixed feelings. On one hand, I sympathized with the horror of her situation, especially when almost none of it is her fault exactly. On the other hand, I can't help but feel that if Carrie had just learned to be a little less noisy and less of an annoying backseat driver, it might not have come to this.

Yasha Jackson camps it up as bitchy new wife Emily. Sleek, sexy and venomous. She's not a nice person, but put in a situation though no fault of her own, and doesn't handle it at all well. Who would, really?

Babs Olusanmokun as Clayton Leigh. Stoic family man. Though I feel like the part near the end where he just drools and stares off into space is his best acting.

Amanda Warren as Clayton's wife Angelica. She does this nice emotional bit with Clayton during a prison visit - very heartrending. After that, the actress is basically reduced to cameos.

The Mood

It begins as a sunny day in some desert, but soon gets into the confines of the titular Black Museum.


The little flashbacks and stories span between mood whiplashes. Sometimes it's all nice and breezy in the day, and then flashes to a nightmare of blood and violence. A lot of it can be claustrophobic especially since a couple stories revolve around someone's consciousness being trapped in either a confined space or an inanimate object (or inside a living person but with no agency).

What I liked

All the little Easter Eggs that appear in this episode that harken back to previous episodes. Black Mirror has always had them, but this episode seems to have Easter Eggs to every single episode in Black Mirror ever, up to this point. We have news tickers referencing multiple previous episodes and displays in the museum doing the same (mugshots, exhibits, etc). The names of the mice are Hector and Kenny, two of the main characters in Shut Up And Dance. And near the end, we see a sly reference to the episode Be Right Back, when it's revealed that the name of the nearby gas station is BRB Connect!

And of course, there's TCKR, the company being featured in San Junipero. They feature pretty strongly here, too.

Nish charging up her electric car using solar power is a fun nod to Nosedive.

Who wrote Rolo's dialogue? Whoever they are, they deserve an award.

Eventually, he dick-pukes a little baby paste up her wazoo which takes hold. Before you know it, out pops a boy. Boom. They're a family unit.


The part where Nish whispers "Happy Birthday" to her dad is really heartwarming, not that it has anything to do with the overall plot.

The first mini-story was great. Started out as useful tech, segued into the applications for sex, and turned out to have tragic consequences.


I especially love the second mini-story where Jack loses his privacy and Carrie loses her agency. This is very characteristic of Black Mirror. In particular, Carrie's utterly horrible fate is to be trapped in an inanimate object, being able to only say "Monkey loves you" and "Money needs a hug".


That final mini-story now... that takes the proverbial cake. But it would have been a lot less flavorful without the earlier two stories giving it context.

What I didn't

Clayton Leigh is a little too calm when being executed. Granted, I don't know exactly how inmates on death row typically act, but it feels like it shouldn't be that stoic.

Conclusion

Black Museum has just about everything you could want in a Black Mirror episode - swearing and violence, human beings being dicks to each other and abusing technology in the worst ways possible, call-backs to previous episodes, nasty twists at the end (and because there are different stories in this one, -multiple- different nasty twists). I really enjoyed this one.

This is vintage Black Mirror, all right. Extra emphasis on human beings being scum. Love it!

My Rating

9.5 / 10

Final thoughts on Black Mirror Series Four

The first half of Series Four was decent, with Crocodile being one of my least favorite episodes while still managing to be watchable. 

However, Series Four really picked up its game with the latter half with Hang The DJ and Metalhead. And it had a hell of a strong finish with Black Museum. An improvement on Series Three, for sure. This just keeps getting better.

Monkey loves you,
T___T