Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Saturday, 20 June 2026

Web Tutorial: Bus Arrival App, Redux

Two years ago, I took you through the creation if this charming little app that could show you when your bus was arriving. And I took it on a rigorous test run that lasted that duration. In the process, I discovered what worked, and what needed work. Today I am going to be taking you through some upgrades I have done.

Don't look so shocked. Software is not dead. It evolves. Especially useful software.

Some problems I fixed...
- added visuals for bus types and capacity
- simplified data flow
- color scheme

Let's get to work! We will first streamline the data flow.

The first thing we'll want to do is remove the JavaScript. This upgrade removes all JavaScript in lieu of UI simplicity. To that end, this entire section needs to go.
<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>


Remove this entire div. We want everything to be visible when the data is fetched. No more strategically hiding some of it. This means there are less steps for the user to go through, reducing interface friction.
<div id="bus" style="display:<?php echo (count($buses) == 0 ? "none" : "block");?>">
    <h1>&#128655; BUS SERVICES</h1>
    <?php
    foreach($buses as $bus)
    {
    ?>
        <button onclick="showArrivalFor('<?php echo $bus->ServiceNo; ?>');">
        <?php
            echo $bus->ServiceNo;
        ?>
        </button>    
    <?php    
     }
     ?>
</div>

<br />


Remove this too. We won't need it any more.
#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;
}


In this section, the div should still be styled using the arrival CSS class, but the style that hides it, should be removed, as well as the id attribute.
<?php
    foreach($buses as $bus)
    {
?>
    <div class="arrival">
        <h1> BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>
        <?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>";
            }
        ?>
    </div>
<?php      
    }
?>  


So far so good....


Next, the Color Scheme

Now here's a bit of styling. I enlarged the front to almost double what it was previously, changed the background color to orange, and gave container a white translucent border.
body
{
    background-color: rgb(200, 150, 0);
    font-family: sans-serif;
    font-size: 25px;
}

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


I also removed some of these properties. They're no longer necessary.
#container div
{
    /* border-radius: 20px; */
    /* border: 3px solid rgba(100, 0, 0, 0.2); */
    padding: 0.5em;
    color: rgb(0, 0, 0);
}


That wasn't too hard!


More changes. A couple things are happening here. I remove borders from the rendering of the textbox and button for a clean flat look. I also change the button and hover color.
#stop input
{
    border-radius: 5px;
    border: 0px solid rgba(0, 0, 0, 0);
    padding: 5px;
    width: 10em;
    height: 1em;
}

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

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


While we're at it, let's declutter by removing these icons.
<!--<h1>&#128655; BUS STOP <?php echo $busStop;?></h1>-->
<h1>BUS STOP <?php echo $busStop;?></h1>


<!--<h1>&#128652; BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>-->
<h1>BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>


Looks cleaner now, doesn't it?


In fact, let's clean this up even more.
<!--<h1>BUS <?php echo $bus->ServiceNo; ?> ARRIVAL TIMINGS</h1>-->
<h1><?php echo $bus->ServiceNo; ?></h1>


In the CSS, we provision styling for all h1 tags in arrival. The important thing is that it's floated left. The rest is just aesthetics. I'm going for white text on a yellow background, with rounded corners.
#stop button:hover
{
    background-color: rgb(150, 50, 0);
}

.arrival h1
{
    background-color: rgb(255, 200, 0);
    color: rgb(255, 255, 255);
    border-radius: 5px;
    border: 0px solid rgba(0, 0, 0, 0.5);
    padding: 5px;
    width: 4em;
    height: 40px;
    font-size: 30px;
    font-weight: bold;
    float: left;
    text-align: center;
}

</style>


So now that long-ass title has been reduced to a number.


Now provision some styling for h2 tags. We want them to be a more rounded white block, and appear to the right of the bus number. Thus, floating left is a must.
.arrival h1
{
    background-color: rgb(255, 200, 0);
    color: rgb(255, 255, 255);
    border-radius: 5px;
    border: 0px solid rgba(0, 0, 0, 0.5);
    padding: 5px;
    width: 4em;
    height: 40px;
    font-size: 30px;
    font-weight: bold;
    float: left;
    text-align: center;
}

.arrival h2
{
    background-color: rgb(255, 255, 255);
    border-radius: 15px;
    border: 0px solid rgba(0, 0, 0, 0.5);
    padding: 5px;
    width: 7em;
    height: 40px;
    font-size: 25px;
    font-weight: bold;
    float: left;
    text-align: center;
    margin-left: 0.5em;
}

</style>


But oops, this is a mess.


Add this line here to make sure floats are cleared.
    <?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>";
        }
    ?>
</div>
<br style="clear: both" />


All better now.


Presenting additional data

The final part is here. I want to show bus type and capacity, which is data already present in the API response. I simply did not make use of it the last time. Time to address that oversight!

First, let's relocate the logic to a function, so that the heavy lifting gets concentrated in one place. We'll create busArrivalDisplay() shortly, and retain formatArrivalTime().
<?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>";
    }
*/

    if ($bus->NextBus)
    {
        echo busArrivalDisplay($bus->NextBus);
    }

    if ($bus->NextBus2)
    {
        echo busArrivalDisplay($bus->NextBus2);
    }

    if ($bus->NextBus3)
    {
        echo busArrivalDisplay($bus->NextBus);
    }
?>


In here, we modify formatArrivalTime() slightly to replace "T". It may or may not come up, but why take the chance, eh? Then create busArrivalDisplay(), with obj as a parameter. obj will contain all the information you need. The classes here are based on the Load property in the returned response.
function formatArrivalTime($strTime)
{
    $newStr = str_replace("+08:00", "", $strTime);
    $newStr = str_replace("T", " ", $newStr);
    return date("h:i A", strtotime($newStr));
}

function busArrivalDisplay($obj)
{
    $html = "<h2 class='capacity_" . $obj->Load . "'>";
    $html .= formatArrivalTime($obj->EstimatedArrival);
    $html .= "</h2>";

    return $html;
}


We will make use of the various possible values of capacity. In the CSS, we define different colors for capacity. "SEA" means that there are seats, so the color is green. "SDA" means that there's standing space, so we use yellow. "LSD" means that there's limited standing space. The bus is almost full. So use deep red for this.
.arrival h2
{
    background-color: rgb(255, 255, 255);
    border-radius: 15px;
    border: 0px solid rgba(0, 0, 0, 0.5);
    padding: 5px;
    width: 7em;
    height: 40px;
    font-size: 25px;
    font-weight: bold;
    float: left;
    text-align: center;
    margin-left: 0.5em;
}

.capacity_SEA
{
    color: rgb(0, 200, 0);
}  

.capacity_SDA
{
    color: rgb(200, 200, 0);
}    

.capacity_LSD
{
    color: rgb(200, 0, 0);
}
</style>


So now we have differently-colored times.


Now for bus types. Basically, I only care about the difference between single and double decker buses. Therefore, all other bus types will just use the same image as the single decker bus.

I used some stock images for this. I actually have only two images. The others are all duplicates with different names.

(img)
icon_.png
icon_BD.png
icon SD.png



icon_DD.png


Then we add this line. This adds a transparent PNG, according to the bus type, to the information.
function busArrivalDisplay($obj)
{
    $html = "<h2 class='capacity_" . $obj->Load . "'>";
    $html .= "<img height='30' src='icon_" . $obj->Type . ".png' /> ";
    $html .= formatArrivalTime($obj->EstimatedArrival);
    $html .= "</h2>";

    return $html;
}


Beautiful!

Enjoy this version!

I really think it's more user-friendly, especially on mobile. Before this, I tested it on desktop, but it doesn't really make sense to do that because, well, if you're trying to look up bus arrival data outdoors, why would you be using a laptop? Yeah I know, I dropped the ball. It's on me. Hopefully this makes up for it!

Stay bus-y,
T___T

Monday, 27 April 2026

JavaScript's non-existent relationship to Java

Despite the fact that I can no longer, by any stretch of the imagination, be referred to as a "beginner" where my career is concerned, I sometimes do like to read beginner books on tech. It's oddly soothing. There's also plenty I can learn in terms of how to communicate tech concepts and ideas, from the authors of such books, if not the actual tech itself.

And this is one such book that I picked up from the neighborhood library recently - How to be a Web Developer, by Radu Nicoara.

This book.

Now, this isn't one of my Reference Reviews - I didn't finish reading the book and this would be dishonest. Radu Nicorara probably knows his way around the building blocks of the World Wide Web and has, again, probably done a whole lot more than I have. After all, he published a book. And I give him all the credit in the world for even attempting it.

However...

...once I got to Page 60 (or thereabouts), I encountered a statement that was so egregious that it took me out of reading the book entirely. Not that I ever found the book all that engaging in the first place.

This passage shocked me.



JavaScript is a scripting language (meaning the code is not precompiled) that's derived from the Java programming language, hence the name.
I was in complete disbelief when I saw this. Just to be sure, I sent a photograph of the page to Meta AI, and Meta AI being the nice little bot it was, it described the passage as "a bit misleading".

A bit misleading?! Try "completely false".

The error

For anyone who might be tempted to repeat this, JavaScript is not derived from Java. Aside from the fact that they may both be described as programming languages (coding pedants may insist that in JavaScript's case, it's a loose description) they don't actually have anything to do with each other.

JavaScript began life as a loosely-typed client-side language meant for browsers to interpret. Java was (and still is) a strongly-typed compiled programming language. The names are similar, and the syntaxes are similar. But that's where the similarities end, and even these similarities can't be used as evidence for JavaScript's relationship to Java.

In fact, JavaScript's original name was Mocha. Yes, as in the coffee. It was changed to "JavaScript" as some kind of marketing ploy to mislead people into thinking it was a child of Java. Well, guess it worked!

Fancy a cuppa Mocha, luv?

This reminds me of an encounter on the Clubhouse app where I heard some American woman make the ridiculous claim that in the Chinese language, "the words for danger and opportunity are the same".  John F Kennedy, the 35th President of the USA, was the first to say this back in 1960, and he was wrong. In Chinese, danger is "危机" and opportunity is "机会". Both words contain the word "机", but "机" is also a suffix commonly used to describe machines such as "飞机" (flying machine, a.k.a aeroplane), "手机" (hand machine, a.k.a mobile phone) and "耳机" (ear machine, a.k.a earphones). At the risk of stating the painfully obvious - aeroplanes, mobile phones and earphones have fuck-all to do with danger or opportunity, just as JavaScript has no relation to Java.

Which tells us a couple things - just because two words sound the same or contain subsets of each other, does not make the things they are describing, related. Thus, just because Java and JavaScript both contain the words "Java", it doesn't follow that they're related in any way. The second thing this tells us is, if you don't speak a language, maybe keep the witty quotes to a minimum unless looking stupid brings you deep emotional satisfaction.

As for syntax, both Java and JavaScript's syntax is based on C. Curly brackets, semi-colons, function declarations and so on. But this similarity is not confined to Java and JavaScript. Several other languages such as PHP and C# also have great syntax similarities with Java. In terms of similarity, C# is even closer to Java than JavaScript is.

All in all...

It's not my intention to jump on Nicoara for this error. Whomever his editor was, shares the blame for this. And this glaring factual error aside, what little I read of his book seemed sensible. Therefore, I didn't contact Nicoara and inform him of this boo-boo. What good would it do? It's not like one can un-publish this book.

Besides, I'm not exactly perfect. Early in my blogging days, I probably made my fair share of factual errors. Though, in all fairness, it's not like I'm profiting off my blog, or asking people to pay for it.

All that aside, I used this as a teachable moment. Even if that little piece of programming history I taught was dryer than a nun's coochie.

Java nice day!
T___T

Sunday, 29 March 2026

Web Tutorial: Chuck Norris Memorial

A legend has left us. On the 19th of this month, one Chuck Norris, martial artist and action movie icon, passed away. One of the things that really stood out in the Chuck Norris mythos was... well, the Chuck Norris mythos. Remember back in the 2000s, how popular "Chuck Norris facts" became?

Well, today, in loving ass-kicking memory, we'll do something like this! It'll be a page that returns a random Chuck Norris fact each time. But this is a tech blog, so the fact has to be tech-based! And this is an image that we'll be using, which I generated using Meta AI.

chucknorris.jpg

Let's begin by creating a PHP page. We'll deal with the HTML portion first. We'll also use some jQuery UI to create nice animations. Note that in the body, we have div tags styled using the CSS classes number, fact and rip
<!DOCTYPE html>
<html>
  <head>
    <title>In Memory of Chuck Norris</title>

    <style>
  
    </style>

    <script src="https://code.jquery.com/jquery-3.7.1.js"></script>
    <script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>

    <script>

    </script>
  </head>

  <body>
    <div class="number"></div>
    <br />
    <div class="fact"></div>
    <div class="rip">R.I.P 19<sup>th</sup> March 2026</div>
  </body>
</html>


Let's add some PHP. This currently is just one line, declaring fact as a string. The value is one of my favorite Chuck Norris "facts". In the div styled using the CSS class fact, display the value of fact. And in the div styled using the CSS class number, let's have a random number to humorously display which number this "fact" is supposed to be.
<?php
  $fact = "Chuck Norris can divide by zero";
?>


<!DOCTYPE html>
<html>
  <head>
    <title>In Memory of Chuck Norris</title>

    <style>
  
    </style>

    <script src="https://code.jquery.com/jquery-3.7.1.js"></script>
    <script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>

    <script>

    </script>
  </head>

  <body>
    <div class="number">Fact #<?php echo rand(100, 100000); ?>:</div>
    <br />
    <div class="fact"><?php echo $fact; ?></div>
    <div class="rip">R.I.P 19<sup>th</sup> March 2026</div>
  </body>
</html>


This is just text right now.


Now let's style the body tag. We first want to use the image as a background.
<style>
  body
  {
    background: url(chucknorris.jpg) left top no-repeat;
    background-size: cover;
  }  

</style>


Then we want to style the text. I made it large font, with a white outline using the text-shadow property.
<style>
  body
  {
    background: url(chucknorris.jpg) left top no-repeat;
    background-size: cover;
    font-size: 60px;
    font-family: georgia;
    text-shadow: -2px -2px 2px rgb(255, 255, 255), 2px -2px 2px rgb(255, 255, 255), -2px 2px 2px rgb(255, 255, 255), 2px 2px 2px rgb(255, 255, 255);

  }  
</style>


Nice contrast, eh?


Now let's focus on the CSS classes number, fact and rip. It's mostly positional. I made number bolder and floated it left. fact is also floated left. rip has position property set to fixed and is anchored to the bottom right of the screen via the right and bottom properties. I'ave also adjusted the font size.
<style>
  body
  {
    background: url(chucknorris.jpg) left top no-repeat;
    background-size: cover;
    font-size: 60px;
    font-family: georgia;
    text-shadow: -2px -2px 2px rgb(255, 255, 255), 2px -2px 2px rgb(255, 255, 255), -2px 2px 2px rgb(255, 255, 255), 2px 2px 2px rgb(255, 255, 255);
  }

  .number
  {
    font-weight: bold;
    width: 10em;
    float: left;
  }

  .fact
  {
    width: 20em;
    float: left;
  }

  .rip
  {
    font-size: 0.5em;
    height: 1.5em;
    position: fixed;
    bottom: 0;
    right: 0;
  }    
  
</style>


See what I mean?


OK, next up... animation! For this, we want to set the display property of the fact CSS class, to none. This effectively hides the "fact". That's because we want to use jQuery to make it fade in.
.fact
{
  width: 20em;
  float: left;
  display: none;
}


In the script tag, do this so that the code only runs once the HTML is loaded.
<script>
  $(document).ready(function() {

  });

</script>


This causes the "fact" to fade in over the course of 5 seconds.
<script>
  $(document).ready(function() {
    $(".fact").fadeIn(5000);
  });
</script>


Then we use the effect() method on this element. The "bounce" effect belongs to jQuery UI, and here we specify a 1 second duration.
<script>
  $(document).ready(function() {
    $(".number").effect("bounce", 1000);
    $(".fact").fadeIn(5000);
  });
</script>


We include an object with the times property set to 5, so that it bounces 5 times in 1 second. (Sounds like a really lousy credit card, but there you go.)
<script>
  $(document).ready(function() {
    $(".number").effect("bounce", {times: 5}, 1000);
    $(".fact").fadeIn(5000);
  });
</script>


See how the "fact" fades in as the "number" bounces!


Now for the most exciting part... leveraging on OpenAI's ChatGPT to generate a random Chuck Norris "fact". For this, we're leveraging on ChatGPT's API. First, declare key, org and url. These should already have been set up as a new project in ChatGPT. Then create headers as an array of strings. This is what we'll be sending to the URL defined at url.
<?php
  $key = "sk-xxx";
  $org = "org-FUOhDblZb1pxvaY6YylF54gl";
  $url = "https://api.openai.com/v1/chat/completions";

  $headers = [
   "Authorization: Bearer " . $key,
   "OpenAI-Organization: " . $org,
   "Content-Type: application/json"
  ];


  $fact = "Chuck Norris can divide by zero";
?>


We then construct the prompt to send. Here. I specify the JSON object that ChatGPT should give me, and explicitly specify the value. I want a Chuck Norris "fact", and I also want it to be tech-related. Because those are the ones I love. That's for content. role is set to "user". All this is in the array, obj, which is in turn part of messages.
<?php
  $key = "sk-xxx";
  $org = "org-FUOhDblZb1pxvaY6YylF54gl";
  $url = "https://api.openai.com/v1/chat/completions";

  $headers = [
   "Authorization: Bearer " . $key,
   "OpenAI-Organization: " . $org,
   "Content-Type: application/json"
  ];

  $messages = [];
  $obj = [];
  $obj["role"] = "user";
  $obj["content"] = "Give me a JSON object with one property. The property should be named 'fact'. Its value should be a string. This should be a Chuck Norris 'fact', relating either to internet, email or software. An Example would be 'Chuck Norris can divide by zero.'.";
  $messages[] = $obj;


  $fact = "Chuck Norris can divide by zero";
?>


Then we create the parent, data. Here we specify the model. Then we set messages, and max_tokens. This one won't be text-heavy. I reckon 500 tokens should be enough.
<?php
  $key = "sk-xxx";
  $org = "org-FUOhDblZb1pxvaY6YylF54gl";
  $url = "https://api.openai.com/v1/chat/completions";

  $headers = [
   "Authorization: Bearer " . $key,
   "OpenAI-Organization: " . $org,
   "Content-Type: application/json"
  ];

  $messages = [];
  $obj = [];
  $obj["role"] = "user";
  $obj["content"] = "Give me a JSON object with one property. The property should be named 'fact'. Its value should be a string. This should be a Chuck Norris 'fact', relating either to internet, email or software. An Example would be 'Chuck Norris can divide by zero.'.";
  $messages[] = $obj;

  $data = [];
  $data["model"] = "gpt-3.5-turbo";
  $data["messages"] = $messages;
  $data["max_tokens"] = 500;


  $fact = "Chuck Norris can divide by zero";
?>


And here's the final use of cURL, to send data to the API endpoint.
<?php
  $key = "sk-xxx";
  $org = "org-FUOhDblZb1pxvaY6YylF54gl";
  $url = "https://api.openai.com/v1/chat/completions";

  $headers = [
   "Authorization: Bearer " . $key,
   "OpenAI-Organization: " . $org,
   "Content-Type: application/json"
  ];

  $messages = [];
  $obj = [];
  $obj["role"] = "user";
  $obj["content"] = "Give me a JSON object with one property. The property should be named 'fact'. Its value should be a string. This should be a Chuck Norris 'fact', relating either to internet, email or software. An Example would be 'Chuck Norris can divide by zero.'.";
  $messages[] = $obj;

  $data = [];
  $data["model"] = "gpt-3.5-turbo";
  $data["messages"] = $messages;
  $data["max_tokens"] = 500;

  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

  $result = curl_exec($curl);
  if (curl_errno($curl))
  {
   echo 'Error:' . curl_error($curl);
  }

  curl_close($curl);  


  $fact = "Chuck Norris can divide by zero";
?>


We grab the response and extract the required value. And then we change fact's value from a hard-coded string, to that extracted value.
<?php
  $key = "sk-xxx";
  $org = "org-FUOhDblZb1pxvaY6YylF54gl";
  $url = "https://api.openai.com/v1/chat/completions";

  $headers = [
   "Authorization: Bearer " . $key,
   "OpenAI-Organization: " . $org,
   "Content-Type: application/json"
  ];

  $messages = [];
  $obj = [];
  $obj["role"] = "user";
  $obj["content"] = "Give me a JSON object with one property. The property should be named 'fact'. Its value should be a string. This should be a Chuck Norris 'fact', relating either to internet, email or software. An Example would be 'Chuck Norris can divide by zero.'.";
  $messages[] = $obj;

  $data = [];
  $data["model"] = "gpt-3.5-turbo";
  $data["messages"] = $messages;
  $data["max_tokens"] = 500;

  $curl = curl_init($url);
  curl_setopt($curl, CURLOPT_POST, 1);
  curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

  $result = curl_exec($curl);
  if (curl_errno($curl))
  {
   echo 'Error:' . curl_error($curl);
  }

  curl_close($curl);  

  $data = [];
  $data["model"] = "gpt-3.5-turbo";
  $data["messages"] = $messages;
  $data["max_tokens"] = 500;

  $result = json_decode($result);
  $content = $result->choices[0]->message->content;
  $content = json_decode($content);


  $fact = $content->fact;  
?>


See? The facts change now.


Different fact.


Another different fact.


R.I.P, Mr Norris!

Rumour has it that you've been dead for years. Death just hasn't plucked up the courage to tell you.

Did you know that Chuck Norris can delete the Recycle Bin?
T___T

Friday, 13 March 2026

Named Versus Positional Notation in Functions and Methods

For as long as I have used functions and methods in programming, the default mode for me has been Positional Notation. Now, one may ask, what's Positional Notation?

Positional Notation is the method in which a function in a programming language identifies its parameters - by the positional order in which they are introduced. This example is in PHP.
function x($a, $b)
{
    //code here
}


In this call to the function x(), the value of a is 100 and the value of b is "abc". This is because the value 100 appears first, as does the parameter a in the function specification for x(). And the value "abc" appears second, as does the parameter of b.
$y = x(100, "abc");


Years back, I picked up Python and found out about Named Notation. This is a function declaration in Python.
def x (a, b):
    //code here


This is the way it's called in Positional Notation. No surprises there.
y = x (100, "abc")


And this is the way it's called in Named Notation! Note that in Named Notation, the argument values are directly assigned to the parameter names.
y = x (a = 100, b = "abc")


Or this. Because in Named Notation, the positional order no longer matters!
y = x (b = "abc", a = 100)


Why I love this...

Named Notation trumps Positional Notation. I'm sorry for fans of the latter; it's not even close.

Getting the order of arguments wrong has introduced many a bug in the code. In the case of a language like PHP, this is made even easier because PHP's parameter positions are notoriously (and annoyingly) inconsistent. Check out the definitions for strstr(), str_replace() and in_array(). The absence of Named Notation, thankfully, appears to have been fixed in PHP 8.0.

Position no longer matters.

Another thing about not needing to adhere to Positional Notation, is that if the programmer decides to add parameters to the function definition later, this makes it easier to do without breaking any existing implementations. In other words, this is great for extensibility.

...and why I don't

For Named Notation to work, a programmer needs to know the names of the parameters of the function or method they're attempting to call. This is often found in the documentation. A badly spelled parameter name could ruin your day.

And in the case of functions with many parameters, this could get cumbersome. On the other hand, Positional Notation is worse if there are many parameters. Far, far worse.

The only, solitary one!

Specifying the name of a parameter could be superfluous if there is only one parameter. After all, if there is only one parameter and only one argument is passed in, it makes sense that the argument is meant for that parameter.

Conclusion

Named Notation is not new, but for some reason or other, it just has not been the default in passing arguments into functions the same way Positional Notation has. It's starting to change, with support for Named Notation taking hold in recent times. This can only be a good thing. I'm digging it.

And that's my position!
T___T

Tuesday, 25 November 2025

Tech skillsets: Go deep or go wide? (Part 1/2)

"Jack of all trades, master of none" is a term I've heard all too often when fellow techies describe my stint as a web developer. Back then, I was a generalist dipping my sticky fingers into every new and shiny tech I encountered. In a sense, I'm still that web developer. Just with more money.

Go deep or go wide?

I want to explore the pros and cons of generalizing as opposed to specializing, especially in the context of today's tech landscape. The industry needs both specialists and generalists. That's a simple fact that shouldn't need some nobody tech blogger pointing out, but sometimes people get overly emotional about defending their stance. Want to specialize? Cool, do that. Want to generalize? Also cool, go crazy. But we need to be cognizant of the tradeoffs.

The case for specializing over generalizing

Before every tech and his dog started calling themselves "full-stack developers", specialists seemed to earn a whole lot of money. That was back when I was reading job ads asking for "deep expertise" and extensive work experience in more narrow scopes such as back-end programming and database administration. Some areas, such as COBOL programming, pay a lot for the simple reason that COBOL is still largely in use but COBOL programmers appear to be a dying breed. I've touched a lot of programming languages, but just enough to qualify as a hobbyist in each one. I have a decent frame for comparison between them - a Python lecturer of mine was actually quite entertained at my comparisons of the language to PHP and Ruby - but that often isn't very useful in the professional sense.

Specialists earn big.

The companies whose budgets are large enough to afford to pay for specialists, also tend to use these specialists for projects that are grand in scale. Projects that actually require deep expertise. Projects that add incalculable value to one's CV.

Deep knowledge is also useful for judging the extent of one's resolve and commitment. After all, it takes plenty of both to spend the effort. I personally know someone who specializes in HTML and CSS. It's a very narrow niche and perhaps not very profitable, but undeniably impressive.

Generalists - quite unfairly, I might add - seem to have developed a reputation for being easily distracted. Lacking the necessary discipline and focus required to specialize. I would actually say it takes an extraordinary amount of discipline to avoid going too deeply down one rabbit hole and shutting out everything else, but that's not the general sentiment. Therefore, in some circles, generalists are seen as those who were unable to specialize as opposed to specialists being unable to generalize.

The conventional advice when it comes to tech specialization, is to specialize in one area while simultaneously being decent in a few related areas. For instance, if you're a Data Analytics guru, you may want to specialize in statistical analysis and mathematics, but at the same time get reasonably good with Data Visualization tools and learn a bit of Python. If you're a primarily a Front-end Developer, learning some simple database concepts would be a useful addition to HTML, CSS and JavaScript. Maybe pick up a few frameworks such as ReactJS or VueJS, just to round things out.

I won't argue against that advice, but these days it feels like nothing is ever enough.

Next

We explore the opposite case!

Saturday, 1 November 2025

The year I finally achieved that JLPT certification

Some say "better late than never". I got a huge dose of that this year as I obtained my Japanese Language Proficiency Test (JLPT) N5 Certificate.

Why was this overdue? Well, you see, because I actually began on this journey at the tender age of 15. I was a Polytechnic student at the time, and this was a supplementary module. At first, things went well. Having received education in Chinese, learning the basic sounds of Japanese was a breeze. Learning the Hiragana and Katakana writing systems wasn't much of a stretch as well; in fact it was significantly easier than reading and writing Chinese characters. Until we got to Kanji, which essentially was Chinese characters.

Ugh, more Chinese.

At which point I lost all interest.

Also, at this time, I had begun an obsession with writing code, and building stuff. Japanese was a pretty language, but it just didn't fit into my world the same way C++, SQL or even QBasic, did.

And the rest, as they say, is history. Even after graduation, not only did I neglect whatever little Japanese I had learned, the next few decades were a disastrous collection of bad career choices, even worse lifestyle choices, and sobering life lessons.

COVID-19 and Clubhouse

Fast-forward to 2021. COVID-19 had the world in its loathsome grip and I, like many others, sought human interaction online. That was when I discovered the Clubhouse app. Through it, I encountered numerous communities, not all of which spoke English, Mandarin, or even Cantonese.

A few of these were Japanese speakers. And some were even offering Japanese lessons. I dove right in, relearning all the basics I had forgotten. Many times, I would simply listen in, try to make sense of the conversation, and Google words that came up. Then I started engaging, hesitantly, in the conversations. I even participated in Mandarin-Japanese exchanges!

Little cultural exchanges.

It was slow going. I wrote an app to facilitate relearning Hiragana and Katakana. I practiced writing every day, religiously. But there was this feeling that I could do more.

That was when someone suggested that I take the JLPT. And from that day forth, I took things up a notch.

Training in earnest

My next step was to install Duolingo on my phone. For the next few years, I faithfully partook of the exercises daily. At the same time, I went onto YouTube to search for JLPT Listening exercises. I didn't really have a sense of how far I had progressed; I just knew I needed to keep going. I've never been brilliant; but what I am good at is being consistent.

One year later, I downloaded the Migii app, and paid the subscription fees for accessing sample JLPT exam questions. With Duolingo, the returns were diminishing. I needed to train a different set of linguistic muscles - the kind used for passing the exam. Duolingo had brought me to a certain point where I could read the Japanese exam questions without too much difficulty... now I had to practice answering them.

The next milestone was hit another year later when, while watching a Japanese TV show, with English subtitles, I noticed something odd. Almost constantly, the subtitles would read "It's OK". Even though "It's OK" was a perfectly reasonable thing to say in the context of the current point of the story, it was a pretty poor translation.

Phrase Literal Meaning English Translation
daijobu It's OK. "It's OK."
dou itashimashite You're welcome. "It's OK."
shinpai suna Don't worry. "It's OK."
anshin shite Relax. "It's OK."
ki ni shinai de Pay it no mind. "It's OK."


At this point, I found myself thinking - wow, these translators are so goddamn lazy! They just use "It's OK" for everything!

And my next thought was - hey, if I know this much, shouldn't I be taking the JLPT already?!

The JLPT Test Voucher

That was when I registered for the JLPT on the Japanese Cultural Society of Singapore website. and paid a hundred Singapore dollars for the privilege. A month later, the JLPT test voucher arrived in the mail. The train was in motion; there was no going back.

Meanwhile, I continued training religiously. With Listening practice, especially. Online chatter had it that the recordings would be played only once, so I trained myself similarly, by not rewinding and replaying.

The JLPT N5 Exam

It was July when the day arrived. I head for the Singapore Management Institute where the exam was held, and stood in line with what looked like mostly Burmese folks. Interesting.

The invigilator who took charge of the exam room I had been assigned to, seemed to be Japanese going by the way she spoke English.

Shading answers with a pencil.

The proceedings were charmingly old-school. We were given question and answer sheets. It was all multiple-choice, and the correct answer had to be shaded with a pencil for feeding into a scanning machine. Despite my numerous certificates, I hadn't done this since... 2015? This was because my last couple certifications were earned from doing the coursework and presentations, rather than standardized tests.

The toughest moment in the exam came from the Choukai, which was the Listening portion. Despite my best efforts, my concentration slipped at various points. It was with considerable relief that I handed in my question and answer sheets, and headed off.

In August, I logged on to the JLPT portal to check my results. I had passed, and my results were more than decent. I actually scored higher on Listening than other sections!

The real value of all this

Last September, I got my actual physical certification through the mail. It was a foregone conclusion by that time, but I still felt that little thrill of pride. Job well done, bro, I told my reflection. Not such a big deal in the larger picture, but we've got to celebrate our wins even if they're small. Especially if said win took thirty-three friggin' years to achieve.

My results.

The JLPT N5 Certification isn't going to change my life. As far as professional cred goes, it's barely a blip. Achieving the JLPT N5 Certification probably puts me on par with the average Japanese toddler where the language is concerned. As for the value of understanding multiple languages? That's not much of a flex. This is Southeast Asia; just about everyone and their dog is multilingual.

No; at my age, the act of learning is arguably more important than what's being learned. It helps stave off dementia.

The real value is knowing and affirming, that with sufficient motivation and putting in the time and effort, I can learn pretty much whatever I choose to learn. And that is powerful stuff. In an age where things are constantly and rapidly evolving, the ability to learn shit has become vital - not just in the tech industry, but for life itself.

In hindsight, I should have realized this. How did I learn ASP? PHP? Ruby? VueJS? D3? All by picking up a book, watching videos, visiting websites, and constant practice. Most of the time, it really is that simple. The methods vary, but at the end of the day, it's about the willingness to put in the hours.

The linguistic journey continues!

I do want to see if I can achieve the next rung, the JLPT N4 Certification. Again, I'm not really sure why. Just for the hell of it, I guess. It's not like I plan to visit Japan. It's not like I realistically have anything to prove to anyone.

On the other hand, Korean does seem pretty interesting.

Decisions, decisions...

Ganbarimashoo!
T___T

Friday, 10 October 2025

TeochewThunder: Year Eleven (Part 1/2)

Well, look who turns 11 this year! It's not me (I wish), but it's this blog, of course. This thing here might just be a substitute for the children I'm never planning to have.

Dear God, please no.

In all seriousness though, it occurs to me that the effort taken to maintain this blog and the website has pretty much kept me sane all these years. I read somewhere about journalling with regard to mental health, and it seems that this blog is a great example of journalling. Why's it different from venting on Facebook or X, you might ask?

Well, for one, Social Media posts tend to be a lot shorter and more unfiltered. Which can be a good thing, don't get me wrong, but not necessarily so if you want a more thorough internal audit. Blog posts go through several revisions, as we examine what's going on in our heads, and why, and maybe even how it pertains to the tech space. The final result is a more measured, more self-examined output into the stratosphere. As such, I consider my blogposts of higher quality than a simple vomiting of my initial reactions on Social Media platforms.

That isn't to say I haven't said stupid shit in the past. I absolutely have. But the beauty of time is that as the years go by, I can evolve into less of s shit-talker and more of a shit-thinker. Yikes, that didn't sound better, did it?

Dedication

Also, this is a blog I'm dedicated to.

Dedication is a measure of how consistent you're willing to be in your efforts even without applause or acknowledgement. It's a measure of how much of a shit I give. And I give a lot.

Think about it. In previous years, I could at least justify the effort by the way prospective employers would look at my entire online portfolio. These days, they don't do that anymore (also, I haven't been looking in a while) because even the demos I put out are kids' stuff. I like to think some of it is really well-done, but well-done or not, it's still kids' stuff. Those are just not the things people hire senior developers for, especially not in the age of Artificial Intelligence and Vibe Coding.

So no... there are no longer practical reasons for maintaining this effort. I do these things because I like doing these things.

That's not to say I don't occasionally benefit from a break. And October is my assigned month for that break. Other than this blogpost, there will be no other visible activity. Emphasis on the word visible.

Invisible hands, invisible effort.

You see, as in most software development, the value is largely in the stuff that users don't see. The optimizations. The security fixes. The fine-tuning in the back. That's not to say there's no value in the stuff that's visible, but sometimes I feel like a lot of that is just to placate laypersons who don't know any better.

That's a controversial statement which we should reserve for another day.

To my original point, there is going to be work done. Just not visible work. Mostly prep for year-end, and 2026.

Content

As with last year, I've been making an effort to use less profanities in my writing. Not because I necessarily think the odd (or even frequent) vulgarity is a bad thing, mind you. More because I don't want to develop an over-reliance on anything, not even swearing. I don't want to have to use foul language as a crutch to express myself. It's just poor form. To that end, I am limiting myself to using it only a few times a year in this blog, usually whenever I review a Black Mirror episode. I certainly won't be using them with the same frequency during, say, 2019 to 2022, around the COVID-19 pandemic.

Speaking of which, as the horrors of the past few years fade behind us, I'll hopefully be speaking less about COVID-19 from this year forth. It was a terrible few years, and my emotion-laden rants during that period are evidence of that, but it's time to move on.

You may have noticed that the posts are getting even shorter than they used to. This is not an accident; rather it is the natural evolution of this blog. I wasn't verbally verbose before (at least I hope not) but reading other blogposts and tuning out halfway has made me realize that the lack of attention span on the internet is a very real thing. As a result, I'm going to curb any impulse I may have, to belabor whatever points I may be making.

What else? Yeah I changed the TeochewThunder logo. Talked about that already, didn't I? Hope you like it. If you don't, too fucking bad, baby. It's staying.

Surprise!

This is a tech blog, so I talked a whole lot about tech this year, as always. In particular, I talked about Artificial Intelligence. I suspect that this will be happening with alarming regularity, especially with the frequency with which laypersons feel the need to chime in. Someone's got to show 'em their place! Just kidding... kinda.

As for web tutorials, there's been a nice mix that includes NodeJS and NextJS. and D3. Along with the almost obligatory HTML, CSS, JavaScript sprinkled with the occasional PHP, of course. I started learning NodeJS, as usual, for the heck of it. It increased my understanding of what I was doing with ReactJS and NextJS, so there was value in it.

I've continued to generate images from AI, but the pendulum has swung back somewhat and once again I've begun to see value in using stock photos.

Next

Highs, lows, hits and misses

Saturday, 19 July 2025

Five Reasons to learn Web Development in 2025

Recent events such as the rise of generative AI, have made tech work a little less attractive than it used to be. Web development, in particular, has suffered. That's probaby because a large chunk of web development is automatable, and even before AI came on the scene, there had been numerous tools such as Content Management Systems and Low-code development platforms.

Thus, web development being automated by AI was par for the course.

Robots writing websites.

Still, not all is lost. While web development might have lost much of its luster, there are still good, strong reasons to pick it up in ones tech career. Unlike the tech reporters and HR executives who write listicles like these, I have actually been a web developer before. I speak from experience, my dudes. And following are some of the most compelling reasons I had, in no particular order of importance, for going down this path.

1. No complicated installation

Ever tried to learn a language like PHP or Java? Every single one of these languages requires you to set up some kind of compiler or interpreter environment. PHP requires an Apache server. Java needs the Java Runtime Environment. You can write all the code you want, but until the code gets compiled or interpreted by the environment that you have to install and set up, you're not getting even a Hello World program done.

All you need is a browser.

HTML, CSS and JavaScript, however, do not. All of them already run in any major browser - Firefox, Chrome, and so on. In effect, the environment is right there for you.

This is not to say that you will never need to do any complicated installation. But for the basic building blocks - again, HTML, CSS and JavaScript - of web development, you don't. You will need to do that when you want to pick up a server-side language and maybe databases and definitely for the NodeJS style of development. But for basic stuff? Even the slightly more advanced stuff? Nope, not even a little bit. That is a lot more than you could ever say about other programming languages or platforms.

2. Good skill spread

When you learn web development, you learn HTML, CSS and JavaScript as a base starting point. That's already a good spread right there.

HTML and CSS are where you learn front-end and possibly even design. When you learn JavaScript, in addition to all the things you pick up when learning a programming language such as operators, arrays, branching and iterative logic, you also learn asynchronous operations and DOM manipulation.

A good spread of tools.

That's not to say that other tech disciplines don't have their own unique perks. But where it comes to the skill spread, web development wins. I don't think anything else even comes close.

Once you get past the basic toolset of HTML, CSS and JavaScript, back-end programming and databases will come into play. It's never just web development. Even if you are averse to the thought of being a humble web developer for the rest of your career, there are far worse places to start.

3. Resources

Now, when I say "resources", I don't just mean documentation, references and learning materials, though there's plenty of that, yes. But web development is not special in that regard because any other tech discipline boasts plenty of learning resources and a community dedicated to helping each other learn.

A good learning
community.

Though, in this case, web development has something extra.

You see, every humble HTML page on the internet can have its source viewed and played with in the browser, reverse engineered, and so on. Every URL on the internet is potentially a resource for learning, much like how I learned to cobble together JavaScript widgets decades ago.

In contrast, it's not possible to just take any desktop application and reverse-engineer the code, because the code has already been compiled and is no longer human-readable.

4. Ready use case

Often, when learning a programming language, it's helpful to be able to use newly-acquired skills to build something, so as to really hammer home the muscle memory. Something both relevant and useful, preferably. Not that Hello World programs don't have their place, but if one wishes to level up, better use cases are the order of the day.

And with web development, those use cases are almost too easy to find. Web development creates web pages, at the minimum. And after that, at varying levels of complexity, web applications. One does not have to stretch too far to find something worth building... and because it already exists, you know that it is both worth building and possible to build.

Applying what you learn.

My larger point is that what you learn can readily be applied. Not just in creating and editing websites, but in general software development. This also means that your chances of landing a job with that skillset cannot be understated. In this day and age, web developers are perhaps not nearly as in demand as they were a decade ago, or paid nearly as well, but the skillset goes beyond just web development.

For example, a lot of existing software already leverage things like REST API endpoints. These are basically URLs, which are pretty much the backbone of the web. REST is an almost inescapable part of the whole web development deal. Ergo, if you deal in web development, at some point you are going to be dealing with REST endpoints, which overlaps a large part of software development regardless of discipline.

Or even mobile development. In case you weren't aware, a large chunk of mobile tech is basically HTML, CSS and JavaScript.

I could go on... but do I really need to?

5. No gatekeeping

In the legal profession, there's the Bar Exam. In the medical profession, there's the Medical Regulatory Authority. In tech? Other than job interviews which exist at almost every industry, there's almost no gatekeeping in tech. Even the requirement for Degrees of Diplomas is not a really hard one.

When I say "no gatekeeping", I don't mean that nobody tries to gatekeep. The fact is that many people try to gatekeep, but it just doesn't work because to gatekeep, one needs a unified set of standards. It's almost impossible to establish said standards in a landscape as varied as tech, whose goalposts shift constantly.

The gatekeeper.

And while this inability to gatekeep exists in many areas of tech, none moreso than web development. HTML, CSS and JavaScript are fairly stable at this point, but these are just the base technologies. Their offshoots - frameworks, libraries and the like - keep springing up like mushrooms. And when you consider databases and backend programming languages, the possibilities multiply even more.

All in all, one could come in anytime in web development, and still be relatively fresh and relevant. No one can stop you from making and publishing web pages and applications, not in the same way they can stop you from practising law. You don't need a license to write code, so nobody can revoke it.

Some clarifications

The reasons stated here are in relation to those for choosing other tech fields. Why, for instance, web development when you could go for Data Analytics or cybersecurity? Reasons specific to web development.

I was inspired to compile this list because there are a lot of vague, generic and - to be brutally honest - trite lists out there on the web that extol the virtues of web development. Hopefully this is a better list.

<html>Bye for now,</html>
T___T