Friday, 19 August 2016

Web Tutorial: Schooling You in Rollovers!

As I write this, Singapore is still celebrating the Olympic spirit. In particular, our first Olympic Gold medal ever. Won by a young sprightly lad by the name of Joseph Isaac Schooling, who pipped Michael Phelps to the coveted title in the 100m Butterfly.

Do I have cause to feel proud? Rationally, no. I didn't pitch a cent towards Schooling's endeavor, nor have I been rooting for him since day one. Hell, his name barely registered on my radar (and neither did the Rio Games, for that matter) until he won the race and my Facebook feed positively erupted with the news.

But do I feel proud, nonetheless? Strangely, even though I probably have little right to, yes. This is a momentous occasion for Singapore, the island I was born on, lived on, and will in most likelihood, die on.

Joseph Schooling, like a boss.

Congratulations, Schooling. Well done, young man.

I'll mark this occasion by dedicating the planned web tutorial for this month, to Singapore's first Olympic Gold victory. It's about rollover buttons, and it's been stewing for a little while.

Ahem, so...

One of the most common things on the net is rollover buttons. They've been in effect ever since the first JavaScript snippet. Today, we're going to examine some of the ways they are implemented.

Hold on - some of the ways?

Yes. You didn't think for a moment there was only one way, did you? Hell, no! As technology evolves, so do once-accepted ways of doing things.

For the rest of this tutorial, I will be using some very ubiquitous buttons as examples, ie. Facebook, Twitter and LinkedIn. In particular, we'll use them to link to Joseph Schooling's accounts.

These images should be saved in the "img" directory of your root folder.

rollover_fb0.jpg
rollover_tw0.jpg
rollover_li0.jpg

So, what does a rollover button do?

You move your mouse cursor over the button, and the button changes, showing you that it can be clicked.

Like this - see?

Without further ado, we're going to jump right in!

Using JavaScript and Img tags

For this, we need three more images. These are the images that will be changed to. In animation terminology, both original and new images are known as "sprites". (That's just FYI in case you have a presentation or something and need to sound like you know your shit. Don't worry about it.)

Again, these images should be saved in the "img" directory of your root folder.

rollover_fb1.jpg
rollover_tw1.jpg
rollover_li1.jpg

So we have the original images in HTML, encased in anchor tags. The CSS styling is meant to disable the fugly border thicknesses that sometimes show up on older browsers. (Yes IE, I'm looking at you.)
<html>
    <head>
        <title>Rollover</title>
        <style>
            a img
            {
                border-width:0px;
            }
        </style>
    </head>
    <body>
        <a href="https://www.facebook.com/joseph.i.schooling"><img src="img/rollover_fb0.jpg"></a>
        <a href="https://www.linkedin.com/in/joseph-schooling-1750a9a2"><img src="img/rollover_li0.jpg"></a>
        <a href="https://twitter.com/joschooling"><img src="img/rollover_tw0.jpg"></a>
    </body>
</html>


Now we add this! Run your code. When you move your cursor over the icons, they should change to a lighter shade.
<html>
    <head>
        <title>Rollover</title>
        <style>
            a img
            {
                border-width:0px;
            }
        </style>
    </head>
    <body>
        <a href="https://www.facebook.com/joseph.i.schooling"><img src="img/rollover_fb0.jpg" onmouseover="this.src='img/rollover_fb1.jpg'" onmouseout="this.src='img/rollover_fb0.jpg'"></a>
        <a href="https://www.linkedin.com/in/joseph-schooling-1750a9a2"><img src="img/rollover_li0.jpg" onmouseover="this.src='img/2016/rollover_li1.jpg'" onmouseout="this.src='img/rollover_li0.jpg'"></a>
        <a href="https://twitter.com/joschooling"><img src="img/rollover_tw0.jpg" onmouseover="this.src='img/rollover_tw1.jpg'" onmouseout="this.src='img/rollover_tw0.jpg'"></a>
    </body>
</html>


When we invoke the mouseover and mouseout events in the HTML tags, the URLs of the images are changed accordingly. Not my favorite method. Don't get me wrong, it works. But this is Jurassic-era HTML. There are better ways of doing things now.

Using JavaScript and CSS


Here are the buttons, and some CSS. Note that the buttons aren't images. They're actual buttons. The CSS basically styles these buttons to use the original images as background images.
<html>
    <head>
        <title>Rollover</title>
        <style>
            button
            {
                width:64px;
                height:64px;
                border-width:0px;
                background-repeat:no-repeat;
                background-position:left top;
                cursor:pointer;
            }

            .btn_fb_off
            {
                background:url(img/rollover_fb0.jpg);
            }

            .btn_li_off
            {
                background:url(img/rollover_li0.jpg);
            }

            .btn_tw_off
            {
                background:url(img/rollover_tw0.jpg);
            }

            .btn_fb_on
            {
                background:url(img/rollover_fb1.jpg);
            }

            .btn_li_on
            {
                background:url(img/rollover_li1.jpg);
            }

            .btn_tw_on
            {
                background:url(img/rollover_tw1.jpg);
            }               
        </style>
    </head>
    <body>
        <button onclick="window.location='https://www.facebook.com/joseph.i.schooling'" class="btn_fb_off"></button>
        <button onclick="window.location='https://www.linkedin.com/in/joseph-schooling-1750a9a2'" class="btn_li_off"></button>
        <button onclick="window.location='https://twitter.com/joschooling'" class="btn_tw_off"></button>
    </body>
</html>


So if we add this to the HTML, the mouseover and mouseout events trigger a CSS change, which in effect changes the background image of the buttons.
<html>
    <head>
        <title>Rollover</title>
        <style>
            button
            {
                width:64px;
                height:64px;
                border-width:0px;
                background-repeat:no-repeat;
                background-position:left top;
                cursor:pointer;
            }

            .btn_fb_off
            {
                background:url(img/rollover_fb0.jpg);
            }

            .btn_li_off
            {
                background:url(img/rollover_li0.jpg);
            }

            .btn_tw_off
            {
                background:url(img/rollover_tw0.jpg);
            }

            .btn_fb_on
            {
                background:url(img/rollover_fb1.jpg);
            }

            .btn_li_on
            {
                background:url(img/rollover_li1.jpg);
            }

            .btn_tw_on
            {
                background:url(img/rollover_tw1.jpg);
            }               
        </style>
    </head>
    <body>
        <button onclick="window.location='https://www.facebook.com/joseph.i.schooling'" onmouseover="this.className='btn_fb_on'" onmouseout="this.className='btn_fb_off'" class="btn_fb_off"></button>
        <button onclick="window.location='https://www.linkedin.com/in/joseph-schooling-1750a9a2'" onmouseover="this.className='btn_li_on'" onmouseout="this.className='btn_li_off'" class="btn_li_off"></button>
        <button onclick="window.location='https://twitter.com/joschooling'" onmouseover="this.className='btn_tw_on'" onmouseout="this.className='btn_tw_off'" class="btn_tw_off"></button>
    </body>
</html>


Not my favorite method either. I'll explain why in a bit.

What's wrong with the above two methods?

Firstly, they use JavaScript, which is always a bad idea if you're paranoid about users turning JavaScript off.

Secondly, that's a shitload of HTML code to write for a few crummy rollover buttons. I prefer to reserve HTML for other things.

Thirdly, they involve loading new images. The first time any of these images are loaded, there's always a certain amount of delay. Subsequent times, the images have been cached, so no more delays occur. You can get around this problem by pre-loading images.

Or you could do this!

Using mostly CSS

This method does not use JavaScript, and does not use separate images for the sprites. These are the images we'll be using.

Did I mention that these images should be saved in the "img" directory of your root folder?



rollover_fb2.jpg
rollover_tw2.jpg
rollover_li2.jpg


Note that these images are joined. Here's the HTML and CSS.
<html>
    <head>
        <title>Rollover</title>
        <style>
            button
            {
                width:64px;
                height:64px;
                border-width:0px;
                background-position:0% 0%;
                cursor:pointer;
            }   

            #btn_fb
            {
                background-image:url(img/rollover_fb2.jpg);
            }

            #btn_li
            {
                background-image:url(img/rollover_li2.jpg);
            }

            #btn_tw
            {
                background-image:url(img/rollover_tw2.jpg);
            }
        </style>
    </head>
    <body>
        <button onclick="window.location='https://www.facebook.com/joseph.i.schooling'" id="btn_fb"></button>
        <button onclick="window.location='https://www.linkedin.com/in/joseph-schooling-1750a9a2'" id="btn_li"></button>
        <button onclick="window.location='https://twitter.com/joschooling'" id="btn_tw"></button>
    </body>
</html>


Again, these are actual buttons. Nothing much has changed from the previous method so far, except that a new CSS property has been added - background-position. This may seem utterly unnecessary now given that this is the default setting anyway. But... you guessed it, we're going to change this!
<html>
    <head>
        <title>Rollover</title>
        <style>
            button
            {
                width:64px;
                height:64px;
                border-width:0px;
                background-position:0% 0%;
                cursor:pointer;
            }

            button:hover
            {
                background-position:0% 100%;
            }   

            #btn_fb
            {
                background-image:url(img/rollover_fb2.jpg);
            }

            #btn_li
            {
                background-image:url(img/rollover_li2.jpg);
            }

            #btn_tw
            {
                background-image:url(img/rollover_tw2.jpg);
            }
        </style>
    </head>
    <body>
        <button onclick="window.location='https://www.facebook.com/joseph.i.schooling'" id="btn_fb"></button>
        <button onclick="window.location='https://www.linkedin.com/in/joseph-schooling-1750a9a2'" id="btn_li"></button>
        <button onclick="window.location='https://twitter.com/joschooling'" id="btn_tw"></button>
    </body>
</html>


See what we did there? Each element styled with the CSS class rollover has a new specification - the hover. When you move your cursor over the element, the background-position property of the element changes, giving you the new image, or at least appearing to do so. In reality, it's the same image. It's just that the background position has been offset! When you move your cursor off the element, the original settings kick in.

What's so good about this?

Well, for each button, only one image is used. This saves you the trouble of making different CSS classes for them. Right now you have only three buttons. What if you have fifty? Extensibility FTW!

Also, when the page is loaded, the images are loaded too. Different images don't have to be loaded upon your cursor interacting with the buttons.

Since you're not using JavaScript, you don't have to worry about someone disabling it.

Last, but not least, look at the simplicity of the HTML. All the work is being done by the CSS.

Water way to make buttons, eh?
T___T

Sunday, 14 August 2016

Three Great Virtues (Part 3/3)

Hubris is probably the most misunderstood of all the programmer virtues. But you're in luck - I'm Teochew, and if anyone understands arrogance, it's us.

The Virtue of the Great Programmer - Hubris

Developer ego is more commonplace than you'd expect. Any developer with some experience under his belt is going to be rather opinionated about how things should be done. Programming is about bending the will of a machine to our own, and making it churn out the results we want. It is about creating usable objects out of virtually nothing. It is about dealing in languages many people are too intimidated by to even attempt. And getting paid for it. Why wouldn't we be arrogant? Consider the quote below from Robert C Martin, in his book The Clean Coder.

"Programming is an act of creation. When we write code we are creating something out of nothing. We are boldly imposing order upon chaos. We are confidently commanding, in precise detail, the behaviors of a machine that could otherwise do incalculable damage. And so, programming is an act of supreme arrogance."

Robert C Martin seems to be a bit of an extremist in his views, and more than a little verbose. But in this case, he hit home for me right there.

But... but, but.

Why be modest when
you're that good?


In order for hubris to be a virtue, it has to work for you. It has to help you in your development. It has to drive you.

It has to spur you on to create products that people can only praise. Any code attributed to your name has to achieve great things. That arrogance manifests itself as pride in your work.

It has to inspire you to go boldly where no one has gone before. "A hundred programmers have failed? Well, I'll be the hundred and first." "Better men have tried and failed? Bitch, there ain't no better man." In fact, I believe that it is this same audacity to try something different, something unthinkable, that separates great programmers like Bill Gates (daring to succeed despite dropping out of university? The sheer gall.) and Linus "I'm always right" Torvalds from the rest.

How not to be Arrogant

Some forms of arrogance manifest as a belief that one has already learned all that is worth learning, and there is no need to keep exploring. That's arrogant, sure... it's also foolish. Dangerously so. Technology is constantly evolving. As I type this, a few million hackers around the world have figured out newer and more insidious ways to breach web security. New frameworks are threatening to render the ones you use obsolete. New features in your favorite programming language are causing older features to be deprecated. Going down this path is a sure route to ruin. There's a place for arrogance. Not so for complacency.

Refusal to listen to feedback is another dangerous manifestation of arrogance. Sure, not all feedback is created equal. If, for example, you haven't written a line of code your entire misbegotten life and have the audacity to comment on my professionalism, be prepared to be very firmly put in your place. On the other hand, working too close to the product can lead to blind spots, and sometimes - just sometimes - fresh perspectives are helpful even if they are from laypeople. There's also a tendency for a developer's ego to lead to defensiveness - such as refusing to concede an argument or admit that someone else knows more than you do. That is insecurity. If you're confident enough in your own abilities and value, you don't ever need to travel that rocky road.

Then there's the Not Invented Here syndrome. The pragmatic developer understands that there is no shame in collaboration or leveraging off someone else's work. "Real devs code from scratch"? What kind of egoistical rubbish is that? No matter what you do, you're leveraging off the work of Ada Lovelace, mother of the modern computer. Want to be a "real dev"? Go re-invent algorithms!

So...

Are you an adequate, good or great programmer?

This is, as you may have suspected, just my opinion. There are many ways to interpret the words of Larry Wall. In fact, I have no real business telling anyone how to achieve greatness in programming - after all, I'm just about adequate myself, on some days anyway. Like many people, I have my moments. Some days I feel like I'm Neo from the Matrix, and some days I wonder why I'm even employed.

But in general, yes, most developers fall around the "adequate - good" axis, with only the top echelons making it into the "great" category. Still, "adequate" is a good goal, and "good" is a respectable one.

Be virtuous!

Too impatient to sign off properly, too lazy to care.
T___T

Friday, 12 August 2016

Three Great Virtues (Part 2/3)

Mastered laziness yet? Or at least gotten the correct attitude down? If not, keep at it until you do.

If you have gotten yourself into that correct mindset, read on, you lazy bastards.

The Virtue of the Good Programmer - Impatience

Why is impatience "good", while laziness is merely "adequate"? Because automating tasks is only the first step. Having your solution work is the minimum acceptable outcome. That makes you adequate. In order to ascend to the next level, in order to be considered "good", your code should not just work.

Work harder, slave!


Impatience drives the programmer to further improve his work. The code does not merely run; it has to fly. It cannot only solve that problem; it must solve that problem in spectacular fashion. The impatient programmer always wants more out of his code. Impatience is what you have when you work tirelessly for several nights in a row just to shave off a few milliseconds from the execution time of your code. It's personified by the developer who relentlessly idiot-proofs his system so that all user input is validated and in some cases, even anticipated.

There's a great deal of irony in the fact that in order to exercise impatience where his work is concerned, the programmer has to very patiently improve on his solution.

How not to be Impatient

Testing the solution is often a very tedious process. In order to be done properly, multiple scenarios and edge cases have to be drawn up. Every moving part in the code is a new potential point of failure. Is it any wonder that some people make their living on testing alone? Because not every programmer can do it. Of course, there are those who are so impatient that testing is a waste of time for them. Take note; that is the wrong way to be impatient. In fact, that isn't even being impatient - just stupid.

The wrong brand of impatience can also cause developers to cut corners during the development process - not in terms of quality, but in terms of communication. There have been times during my career where things were moving too slowly for my liking - I badgered colleagues for specifications, took things into my own hands and generally jumped the gun. This resulted in systems that sometimes did not function as expected, and sometimes deviated wildly from user expectation. My mistake was not taking the extra time to check with the users that I had understood their intentions correctly. This resulted in work they couldn't use, and a waste of company time. Sure, I leveled up in the process. Sure, I had fun doing it. But the company wasn't paying me to level up, or entertain myself on their time. It was paying me to get work done. And on that count, I failed. An employer once described me as a race car achieving great speed, but in the wrong direction. That wasn't a compliment.

It probably should also go without saying that the wrong brand of impatience can hurt a programmer who gives up too easily. Things rarely make sense right away, and if a problem isn't yielding a solution right away, approach from another angle. Time spent on understanding something is rarely time wasted.

Next

We examine Hubris.


Wednesday, 10 August 2016

Three Great Virtues (Part 1/3)

Larry Wall, creator of Perl, is also the author of Programming Perl. In it, he said something that has inspired me profoundly as a web developer.
"We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris."


Now, there have been numerous interpretations of these virtues. But we're not going to bother with those; I'll be providing my own take on this. (What? Last time I checked, this is my blog.)

So the burning question - why are these virtues? In most other contexts, they would be considered sins. However, not just any lazy, impatient and arrogant SOB can be considered a great programmer. In fact, it takes a special kind of lazy, impatient and arrogant SOB to be a programmer at all. And I humbly submit that these three virtues are stated in that order for a good reason - they separate the adequate from the good, and the good from the great.

The Virtue of the Adequate Programmer - Laziness

If you remember nothing else about programming, remember this: minimum input, maximum output. All programming is about solving problems and automating tasks. Whatever fancy new gimmicks and technological advances the next twenty years throws at you, philosophically, programming does not change. This has been, is, and will always be; the one truth about programming. Whatever languages you use, whatever platform you swear undying loyalty to, it all goes back to this in the end - minimum input, maximum output.

The ultimate aim of any program is to make life easier. Because the awful alternative is more work. Not just more work - more boring and repetitive work which would be better done by machines.

Make the slaves do the work.


Programmers are always looking for the shortest, most direct route from Point A to Point B. They are always looking for a way to reduce that repetitive, monotonous task into a series of processes and outsourcing them for a dumb machine to execute. In other words, programmers are the taskmasters, and computers are the slaves. If that's not lazy, I don't know what is. The question is invariably "can this be automated?" followed by "how much can this be automated?".

Human beings get distracted. They get bored. They get frustrated. Machines don't. And therefore machines are the perfect candidates as slaves to carry out all that mindless work and in the process make life easier for the programmer. Notice how I said "make life easier" twice?

This is virtue numero uno for a good reason - not all programmers have the other two virtues (and therefore not all programmers are good, or great). But all programmers (and their cousins, the web developers) have to embrace this virtue at their core.

How not to be Lazy

Laziness comes in various forms. Not every form of laziness is admirable. If that laziness leads to more work down the road, it's counter-productive.

Copy-pasting code blindly without checking for relevance and room for improvement - that certainly qualifies. It's something I actively avoid.

If the code is going to be reused in the foreseeable future, invest a bit of time abstracting it into methods and subroutines so that it's easy to reuse and maintain. The Don't Repeat Yourself (DRY) principle is applicable here.

Sloppy code, lax security measures, incomplete test cases are all good examples, cases where the programmer couldn't be arsed to close that last loophole. Guilty as charged. Sometimes reality demands that I have to cut corners. It's not an excuse, but sometimes people have to choose between being a bad programmer who delivers, and being a great programmer who's out of a job.

In an age where many great programmers have paved the way for us by writing systems that automate even programming tasks, it's very easy to be lazy in the wrong way. Plenty of developers I know don't bother with the basics because that newfangled framework takes care of it for them. I'm guilty of this too. For instance, garbage collection and memory management is not exactly something I like to concern myself with - though in my defence, as a web developer, my priorities lie elsewhere.

Next

We examine Impatience.

Thursday, 4 August 2016

The Ratings Game

Out of all the job interviews I've ever been subjected to, one interviewing method stands out - the ratings method. Or, to be more specific, the rate-yourself method. That's where the interviewer names several skills - PHP, MySQL, project management, lightbulb screwing, yadda yadda - and the interviewee rates himself from 1 to 10, 10 being absolute guru, and 1 being clueless dolt.

My rating!

This is significant because I find this method of interviewing trite and meaningless, and I've often associated those words with the interviewing methods of non-technical people, such as HR. Unfortunately, this method of interviewing has been conducted by IT professionals. People who should know better.

Here's why I consider this method trite and meaningless.

You can't prove I'm lying!

At least during the interview, anyway. Let's say the interviewee rates himself an 9 out of 10 in C#. He could be lying through his teeth, but how do you prove that? Sure, you could ask him some pointed questions about C# to determine if he's as good as he says, but if you're going to do that anyway, why bother with the ratings? If those ratings are going to play any part in the hiring process, I'm not sure I want to be hired based on that.

Ratings are subjective

What's my 10, and what's your 10? When I asked that question, some interviewers have told me to just rate myself from my point of view. And that's exactly why it's meaningless. The interviewee doesn't even have to lie - he just has to be supremely confident (rightly or wrongly) that he's that good. I mean, some people think their database skills are hot shit just because they know how to join tables. They're not lying when they give themselves an 8 out of 10. They simply suck so much that they don't even know they suck. Classic Dunning-Kruger effect right there.

The goalposts keep moving

If you've spent any time in the web industry at all, you'll understand that things seldom stay still. Every facet of web development is changing, and changing fast. What you know today could be obsolete next week. My 10 now could be a very different 10 in a month's time. Let's say I think someone needs to be able to format text and change colors in CSS in order to get a 10 in CSS. (I don't actually suck that much. It's just an example.) After learning more about CSS and levelling up, I might discover CSS animations and realize that the bar is higher than I originally thought. In fact, the more a web developer learns, the lower he is going to (honestly) rate himself.


Final Thoughts

Is this ratings method going away anytime soon? Your guess is as good as mine. It certainly is a time-saver, if nothing else. Why bother having a long talk with the interviewee and assessing his strengths and weaknesses when you can just reduce it all to a number-guessing game?

Would you say this blogpost deserves an 8/10? 8.5, maybe?
T___T