Some time ago, one of my many intrepid followers pointed out that this blog tested poorly on web page performance according to this Speed Testing Tool. Now, I’m of the opinion that for a personal blog such as this, web performance isn’t really a mission-critical sort of thing, but as a software developer who has often had to work hard to optimize the web applications we delivered to our clients, it kind of became a matter of pride :p
I also ran the site through Google PageSpeed Insights. The results were mostly the same, but the Google site gave me results faster, so this was the one I referenced for subsequent testing. The most important problems to address were:
Optimizing image sizes
Removing render-blocking JS and CSS in above-the fold content
Leverage browser caching (through the use of HTTP headers)
All of these are familiar to me since they are very common performance optimizations done in web applications. However, this blog is running on WordPress, which means I should try to look for existing WordPress-based solutions instead of hacking the code myself. (I used to run a custom-built Django-based blog system here, but I got tired of maintaining it myself so I went for tried-and-true WordPress). Here are the optimizations I ended up doing:
Upgraded to the default WordPress Twenty-Sixteen Theme. Not strictly necessary for optimization, but I was previously using the Twenty-Twelve Theme, and the problem with using older themes is that they may not be using newer web development techniques to improve performance. Also, Twenty-Sixteen looked better haha. And yes, I do use the default WordPress themes. Too lazy (as of yet) to look for a nice custom theme, and I don’t have the design chops myself to build it, so it will do for now.
For the image size problem, I found that the biggest offender was the Sketching Daily post where I broke down how I do my daily sketches. The problem was that I was uploading full-size images of the drawings and they were being inlined into the post – which meant the browser was loading the full-size image even though it was shown in a smaller size on the post itself. Instead, I manually changed the settings of each image in the post to use one of the smaller-size images generated by WordPress on upload. Choosing “Large” here meant the Large one would be inlined, while I could still set the image to link to the full-size one on click. The full size image is a whole fifteen times larger than the “large” image! It’s something I need to remember in the future if I ever upload huge images again. I also found a link that described how to set the default image size (so that it doesn’t default to full size all the time), but I don’t think it’s necessary for now.
To further help with image optimization, I installed the WP Smush plugin, which automatically optimizes (“smushes”) uploaded images. I found that WP Smush reduces the uploaded image sizes by around 10-15% on average, it’s not too bad.
After the above changes, I retest the site:
Much improvement indeed! There’s still a few issues to iron out, but for the most part I’m happy with the results (and my pride has been satisfied :p). I may revisit this issue at a future date to see if there’s anything else I can improve on.
I read an article recently about how we should encourage entrepreneurial spirit in kids from a very young age. It made think of a time when we were kids and we tried running a business
It was a summer from years ago. Perhaps 1988 or 1989, or maybe a year or two earlier, I can’t be sure. I was young, my brother was younger by a few years, my female cousin older by a few years. Back then our families live under the same roof, my grandfather’s house
We needed something to keep us occupied during the summer. We probably already had a Nintendo around this time, but my brother and I were only allowed one hour of video games a day, so we needed something else to fill the time. I think it was my mother who suggested we run a small business over the summer, sell some food things to people
Our house had a sari-sari store. Sari-sari stores are like small family-owned convenience stores in the Philippines, often run out of the house directly, with the storefront little more than holes in the wall that make up the house’s facade. The one in our house had one small window and one large window, each covered by rusty metal bars half a foot apart. It sold soft drinks (cokes and sprites and whatnot), beer to the local tambays, small bags of chips (Chippy, Clover Chips, Tortillos, etc), small chocolates and packs of nuts and such. As kids we spent a lot of free time at the store, especially when the parents were away. After my grandfather died, the store was taken over by a beloved family friend who had been living with us forever. She often indulged us kids our whimsies, which often meant our parents came home to find out they now owed a bunch more pesos to the store. That summer, we had decided to sell ice candy to the people in the neighborhood through the store
You could be forgiven for not knowing what ice candy was, at least if you didn’t live in the Philippines. It’s a treat made out of frozen flavored water, usually in a long plastic bag that gives it an elongated shape. In the US, they might be called “freeze pops”
My parents gave us some “seed money” (and I suppose my uncle gave my cousin some as well). I think my brother and I would have a separate stock from our cousin, but we would both be selling in the same store. We went to the nearby grocery store and bought the materials we’d need: some powdered flavoring and packs of small plastic tubes. When we got home, our mother showed us how to prepare the ice candy. We would mix the flavoring (I think we used orange flavoring. I liked orange back then) in some water, then pour the flavored water into the plastic tubes and tie a knot in the end to seal them. Then we would leave the tubes in the freezer overnight, and we would sell them the next day
I remember them being a hit, especially with the neighborhood kids. We sold them for I think a peso each, or maybe a peso and fifty centavos. (Things were simple and cheap back then.) I think my cousin used slightly larger plastic tubes and sold her ice candies for a bit more. In theory, we would then reinvest the day’s income into more flavoring and plastic tubes for the next day, but I think it turned out that our parents just gave us more money for the next day’s materials. So perhaps it was less of capitalism and more of “here’s a fun way to earn allowance during the summer”
I specifically remember my younger brother enjoying the business and dreaming of making it big as a businessman. His imagined future business was still ice candy. He imagined having an ice candy empire well-known throughout the land, with rich and famous personalities such as the president coming to his stores to buy ice candy. So maybe the exercise did manage to impart a little bit of entrepreneurial spirit to us after all
I remember at the end of that summer, we were happy with the amount of money we had earned, and we talked about doing it again the next summer. But we never did
I had my first taste with working with software testers during my first project where I was involved with porting an old system to a new version of the software. My first task involved porting reports which were to be generated by the users then printed out. The task wasn’t too difficult: basically you took the source code of the report (it was some weird binary format recognized only by the particular reporting tool – that was how it was done back in the day) and open it using the newer version of the tool, and the tool did some sort of migration magic to adapt it to the new format, then you just save it back again. You compile and run the report using the new format and verify that it’s getting the correct output (needs to be the same output as the old format), and that should be it. Most of the time, at least. Sometimes there were some things that the new format couldn’t handle, or maybe there were some minor compile errors after migration, but such problems were easily fixed, so it was pretty straightforward
Or so I thought. All the reports I was porting were being tested by one of my team members, who was also a newbie like me. Coincidentally, both of the testers I had on the project were also ECE graduates same as me; I was the unusual one who took the developer role. They had their own training focused on tester concepts, so initially I had no idea what to expect. When you’re fresh out of school you don’t have any idea yet how much iteration and rework goes into software development, so there’s this attitude of, “Hey it’s working. Looks good!” without being too thorough
I soon found out that the testers were trained to be very thorough, so I would get a bunch of bug reports. One of my testers would print out the reports, both the new format and the old format, and hold both reports up against the light, overlaid on each other. And they had to match, pixel-perfect! If the new report generated in a slightly different manner, that was a bug! (Of course, this made no sense to me, since logically the users wouldn’t care or notice if some column in the report was 1 pixel over to the right compared to the old format, but those were the instructions so whatever). And then they would use like really long nonsense strings in the data, and in some cases it would make the text wrapping in the report work differently, so I had to fix those too. Then one of the testers would print out reports with a lot of data, generating like 30 to 40 pages or more (we wasted a lot of paper in those days), and the pagination had to match exactly between the old format and the new format. And if it didn’t, I had to spend some time poring over the printout to find the exact point at which the pagination changed and what caused it. Eventually I learned a set of tricks and knew what to look out for when porting the reports
When you’re starting out as a software developer and you’re first introduced to the idea of QA or software testers, there’s a slight tendency to be offended or defensive about bug reports and to be a bit annoyed at the testers. After all, these are people whose job is specifically to find your errors! It’s a problem especially if you have a sense of pride about your work, but once you let go of that pride and recognize that you are not your code, you get to realize that you and the testers are working as a team. The testers are the shield that make sure that stupid stuff you missed or overlooked doesn’t get sent to the users. It’s like how in a buddy cop movie you need to have a partner to watch your back or to cover the other exit so that the bad guy doesn’t get away
After working with the same testers for some time you get used to their individual quirks and figure out which bugs they are more likely to find, so you start focusing on those areas more. You also learn some tricks to sometimes troll around with them especially when you get annoyed with too many bug reports
One of my favorite things early on in the same project was when I would send one of programs over for testing. In addition to the reports, often we would also be doing forms running using the same tool. In those days, we didn’t yet have Hudson or Maven or Ant any sort of automated build system. We would commit our source to version control and generate the binary file manually and copy the binary file over into a shared network drive. And there was no versioning on the network drive, just one folder where all the binaries were. Then we can tell the tester, hey you can test so-and-so program now
The tester would copy the binaries from the network drive to their own machines for testing, and after a while he would come back with some bug reports. The bug reports would be logged in an Excel file (we didn’t have any bug tracking software then either), and I would do a quick skim, and if the changes were easy enough (minor UI stuff), I’d do some quick edits, rebuild the binary, and copy it to the network drive. Then I would message the tester, pretending I’d just seen the bug reports, “Hey, these bug reports don’t seem right. I think you forgot to get the latest files from the drive.” And sure enough, they get the latest files and check again and the bugs would already be fixed. I managed to do this a couple of times before my tester caught on
With the advent of dedicated test servers and modern build scripts, of course this was something I couldn’t regularly do anymore – although once or twice I did have the opportunity to do a live edit on a test server (to verify my fix works) and troll the tester a bit by telling her it worked fine!
After a few months of working with testers, you quickly get used to working with them and get into a good rhythm. You’re kind of partners in crime, except instead of crime it’s quality in software programs. Even with modern developer unit-testing and automated testing practices, having a second set of eyes looking at your program and attacking it from different angles helps improve the quality of the system. A good tester is the shield to the developer’s sword, they make sure the developer keeps his guard up and doesn’t lose to his own mistakes
Grammar note: “Biased” is an adjective. “Bias” is a noun. It is not appropriate to say that a person or an entity “is bias”. Unless you are talking to like a prejudice elemental or something (takes note of that for hypothetical hipster RPG)
In a (long-winded) discussion during the recent election period, someone told me that I “obviously had a bias” and my answer was “Of course I do! Everyone does!” People have different histories and backgrounds which means for any given topic they are likely to start from different points. These biases are perfectly okay and healthy and they’re called opinions. (Cue quote about opinions being like assholes). Example: I’m not in favor of the death penalty therefore I’m biased against candidates that want to promote it
Although we are all entitled to our own opinions, many times we are called upon to make objective judgments. Common examples are jury trials, elections, or when you’re a judge in some contest. During these instances we have to be careful to weigh our own biases and opinions objectively to make sure we are giving a fair judgment
What you do need to note is when you become subject to cognitive biases – unconscious, automatic influences on human judgment and decision making that reliably produce reasoning errors. Be wary of your own cognitive biases and try to mitigate or compensate for them in your reasoning
Research has also shown that people have a bias blind spot. This means we think we are less biased than other people. This is why it is important to examine your own arguments from time to time to see whether you are subject to any of the known cognitive biases. When there is a need to be objective, we need to be extra critical of our own arguments
Often, it is simply a matter of shifting your perspective: think about how a situation looks to people with an opposing point of view to balance out your own views. A sure sign of bias is that you are only aware of the positives of your own point of view and the negatives in others’
Common Evidence of Bias: Your candidate is the best, and you can find absolutely nothing good to say about other candidates.
Another tip: Do not listen only to people who have the same opinion as you do. If you only expose yourself to people who think along the same lines, you are enabling the same set of biases until they become subconscious. This traps you in an echo chamber of people constantly reinforcing the same ideas. A friend and I recently were discussing how certain people react poorly to differing opinions and theorized that maybe that person grew up surrounded by people who enabled his biases
Instead, seek out different opinions. Continuing from the death penalty example above, I don’t shut out discussion from friends who I know to be pro-death penalty. I still read their threads and try to understand their point of view. Listening to a wide variety of different opinions will tend to cancel out your biases with time and will lead towards more objective thinking. For example, when conducting a performance assessment of a team member (something I’ve done often for the past decade or so!), I tend to get other people’s opinions first to contrast with my own, and will often ask someone else whether I might be biased in certain situations. The risk of personal bias is mitigated by sourcing different opinions
At the end of the day, we probably can’t completely eliminate our own biases, but that doesn’t mean we stop trying to be more objective in our thoughts and discussions and decisions
In the modern era of online services and applications, it is getting more and more common to hear of databases and systems being hacked and user data being exposed. The most dangerous of this data is the user’s password since it may allow access not only to your own service but to other services as well. As an application developer, the below is probably the bare minimum you need to know when handling user passwords:
Never store passwords in plain text! This is the most important rule. It means that if your database is ever compromised, the password information will not be exposed
This is true even if your application doesn’t contain sensitive data or would not otherwise cause any problems if compromised. This is because many users will tend to re-use the same password across different services (although they really shouldn’t!)
Use a strong one-way cryptographic hash function to store the passwords. One-way hashes can still be brute-forced, but the idea is that the computational effort to do so will be so large to make it not worth the effort. The most commonly used/recommended algorithms are bcrypt and PBKDF2. One of these should suffice, but take note to check every few years or so if better cryptographic hash algorithms emerge; as technology and hardware evolves and computational power increases, at some point in the future stronger algorithms may be needed (it might take a while though, bcrypt has been good since 1999)
Cryptographic hash functions are designed to be collision-resistant, meaning the result of the hash function will almost certainly be unique. When the user submits a password for authentication, you simply hash it using the same method and compare the hash against the one stored in the database
Use a unique salt per password before hashing. Salting means that you don’t hash the password by itself, you instead combine it with another string before hashing. Not only does this increase the length and complexity of the hashed string, but reduces vulnerability to so-called dictionary attacks and rainbow table attacks. The salt should be different for each user, probably some combination of personal data like the username and a key like the user id stored in your system
Never send passwords in plain text either. You may be tempted to send out an email with the password in plain text on a password reset request. The common practice now is to just generate and send a unique user-specific link to allow the user to set his own password manually
Force good password practices on your users. This means requiring sufficiently strong passwords. Many modern services provide quick feedback on how strong the input password is. Optionally you can also require that the password contains a varied amount of lower case letters, upper case letters, numbers, and other special characters, but this is not really necessary if the passwords are of sufficient length. Also consider requiring users to change their passwords after a set period
You should disallow the most common passwords. A list of the most commonly used passwords (such as “password” and “123456”) are available from previously leaked password hacks. Microsoft has recently started to roll out this sort of check now in their services. Actually, one good idea I’ve heard of before is to have a uniqueness check on the password field – disallow users from having the same password as any other user, but this may not be feasible depending on how you hash the passwords
If your application has a large number of users or is especially critical (anything involving money transactions is a good candidate), you should also consider implementing some sort of two-factor authentication. Most common implementations these days use email, SMS or a mobile application as the second factor
These practices won’t prevent your application from being hacked. In truth, probably nothing can really prevent hacks 100% especially against determined hackers. These are simply mitigation practices you need to be aware of as the application developer to protect your users in case your application does get hacked. Other methods of securing your system may be the responsibility of other roles such as system administrators/engineers or dev ops
Avoid using short, simple, or commonly-used passwords! These are subject to so-called “brute force” attacks where bad actors just try a whole lot of passwords until they find one that works. You don’t actually have to use numbers or special characters (unless the service requires you to do so). What can really hamper password attackers is password length, the longer the better, since the length of the password increases the computational time needed for a brute-force attack. For the most important services, I would suggest a password length of at least 20 characters (although some services won’t allow you to have passwords this long, which deserves a glare from me). If not required to use numbers or special characters, you can simply use a pass phrase composed of multiple English words. This has the pleasant side effect of being easy to remember. As with many things, this is best illustrated by XKCD:
Take note that it’s important to choose passwords or phrases that are not related to common personal information such as birthdays, names of relatives, or anniversaries. This is all information which any attacker might be able to acquire from other sources. This is how Michael Caine’s character in Now You See Me got hacked by the Four Horsemen!
Avoid using the same passwords for every service! This is one of the cardinal rules that Zuck broke causing the hack. A few years back, data from LinkedIn was accessed by hackers including passwords, and the hackers were able to use Zuck’s LinkedIn password to log in to his Twitter and Pinterest accounts
You probably don’t have to use unique passwords for every service – I have a few “low-security” passwords that I use whenever I don’t care about the account being compromised. Most common usage for me is when I need to ask a question on some programming forum (for the rare case that StackOverflow does not suffice)
You need to identify which services are critical to you – the ones you can’t afford to have compromised. Typically (for me at least), this includes financial services (online banking websites), email and social media accounts you use on a regular basis, and probably government services (I don’t have any of those at the moment). For these services you should use different passwords for each one, to protect the other accounts in case one of them gets compromised
In the past few years many major services such as LinkedIn have had their password data exposed (If the programmers were doing their job right, the hackers wouldn’t have been able to decrypt the password data even if they accessed it – but that’s material for another post), so if you’re using a lot of online service, the odds of some of your data getting hacked at some point is quite high
The problem is: most people have trouble remembering one password, how can they be expected to remember multiple passwords and match them to the corresponding service? There are a few of strategies:
Use a password manager program such as LastPass. These programs will randomly generate and store a new password for you for each service you use. A lot of commenters online swear by this, but I’m not a fan of it because (a) I need my passwords everywhere, anywhere, any time. LastPass has an option to sync passwords across the cloud, but it requires a premium account; (b) additional steps when you need to create or store or remember a password; (c) if you lose access to the password manager, you also lose everything else
Use a procedurally-generated password for each service. This is my preferred option. It means that for each service, you construct a password using a fixed set of rules, with the rules taking into account the service itself. A simple example would be using a base password + the service name: with a base password of “horseradish”, you would use “horseradishYahoo” for Yahoo mail and “horseradishFacebook” for Facebook and so on. Of course, if your Yahoo mail account is compromised the hacker can still easily guess your Facebook password, so it needs to be more complicated than that. A better example would be: base password + your favorite Transformer whose name starts with the third letter of the service: for Yahoo it would be “horseradishHound” and for Facebook it would be “horseradishCliffjumper”
Keep a list of password hints written down. Either on paper or on a softcopy document somewhere you can access all the time. Now obviously, if you keep a list of the passwords themselves you risk someone finding that list and accessing all your services. What I like to do is maintain a list of cryptic password hints that really only make sense to me
Memorize them! For the most important accounts (probably the ones that allow access to other services via forgot password mechanisms), you should generate a unique password and eventually memorize them
I use some combination of #2 and #3: for most social media services I use #2 but for more critical services like online banking I use some variation of the procedural rules and maintain a list of cryptic hints that describe how I varied the rules. #2 works fine for social media accounts since I can reconstruct the passwords mentally wherever I am without need to reference a list. For online banking services, I don’t use them that often but they need to be more secure so it’s okay for me to have to reference a list if I forget the passwords. For my primary email accounts, I have a very strong password that I have committed to memory with no hints anywhere
Some random other tips:
Change your passwords on a regular basis. Regularly changing passwords means older passwords can’t be used against you in case they are hacked. It can be as simple as changing your password when you log into a service for the first time in a new year
Don’t share passwords with anybody! Well okay, maybe you can share some passwords with select family members as necessary. But basically don’t give your passwords to anyone you wouldn’t confess murder to. There are still scammers who pretend to be authorities in order to collect passwords and other information from you. Be wary of strangers!
Don’t use any browser feature that remembers the passwords for you. I suggest typing out your passwords every time. Typing them out makes it easier for your brain to remember your passwords. But more importantly, if your machine is compromised by malware, your passwords can be accessed from the browser’s data store
Not really password-related but you should take note anyway: Use two-factor authentication whenever it is available. This is where whenever you login to a service, it will also send you a secret code via another channel such as SMS or email. You then need to input that secret code in the service in order to proceed. This is so that even if your password is compromised, hackers still can’t access your account. This is starting to become more and more common among the widely used services: Google, Facebook, Twitter, and Steam all provide 2FA. Modern online banking services will even require you to use two-factor authentication. (Sadly not all local banks do so)
Well, that post turned out longer than I expected! It might seem like overkill to have overly complicated passwords or password management schemes. If you use any online services which contain important data you can’t afford to have compromised, it’s a necessary evil and well worth the effort
More stories from the early days. Evaluating someone’s programming ability is hard, especially someone fresh out of college. A student’s grades is in no way indicative of how well he can program after all. So most nontrivial programming jobs have some sort of complicated application process involved.
I remember going in and taking an exam. Most application processes will have some sort of written exam to filter out people who look good on paper, but can’t actually do anything. People graduate college all the time without being able to do anything so it’s a fairly good idea
I was expecting the written exam to be programming questions, but to my surprise it wasn’t. The questions were puzzle/problem solving type questions. I think there were 10 questions in all. I don’t remember all of them, but for sure one of them was the pirates puzzle described here: http://www.mathsisfun.com/puzzles/5-pirates-solution.html. I never did find out how many I got correct, although I felt pretty good about my answers for all of them
After passing the written exam, I also had to take a second technical exam. It consisted of a few parts, the first part was they gave me some sort of string-manipulation problem and I had to write a program on a whiteboard and explain and defend it. Nowadays if you asked someone to write a program on paper or on a whiteboard during an interview, it would kind of look ridiculous since it doesn’t reflect a realistic scenario of how programmers work these days (i.e. with the internet and IDEs and autocompletes and whatnot), but that was how things were done back in the day
I hadn’t done much programming outside of using C, so that’s the language I used to provide my solution, but in theory I could have just used some sort of pseudocode since they don’t require you to use specific languages. As a programmer applying for a job, I would recommend prioritizing opportunities that don’t require you to know a specific language or set of languages. You’ll learn and grow a lot more as a programmer
After leaving me in the room for thirty minutes, the interviewer came back and I had to explain the program I had written on the whiteboard. It was a typical string-manipulation problem designed to see how well coders think through the process. I don’t remember the details too much, but I remember getting into a debate with the interviewer about the expected behavior for the C function strcpy(). I didn’t want to appear too argumentative, so even though I believed I was right (and I confirmed it afterwards!) I just let it be after insisting a couple of times
After the programming question, I got asked an “impossible question”. This is another type of interview question that has mostly fallen out of favor these days. The idea of an impossible question is basically the interviewee tries to approximate an answer to a question that would generally take a lot of research to answer. The interviewee has to explain his reasoning of how he would estimate the answer, and from there the interviewer can make a judgment of how well thought out the interviewee’s processes are. I didn’t know about this style of question ahead of time of course, this interview was the first time I’ve encountered it. I actually still remember the impossible question asked of me: I was asked how many people ride the Metrorail (MRT3) in Metro Manila on a daily basis. This was in 2002, so the MRT3 had only been out for around 3 years and wasn’t quite as congested as it was now, so I could make some reasonable assumptions like each train arrives at each station every 5 minutes, each car usually houses 300 people on average, etc, and I think I gave a pretty reasonable answer
This style of recruitment process was popular at the time, more than ten years ago. Companies like Microsoft were well-known for it. In fact many potential programming job applicants would be advised on internet forums to google “Microsoft interview questions”, and many of them became so well-known MS was forced to revamp its processes as well
With the problem solving, the code walk-through and the impossible question, the focus was finding not necessarily people who were very good at coding per se, but rather people who exhibited a strong analytical approach to problem solving
These days the recruitment process is very, very different. In most, if not all companies, the written exam will focus on technical, coding questions. You’ll be given sample code and need to try to identify the problems with the code. A friend even had to answer questions over the phone about details of Java syntax (pretty useless questions if you ask me)
And instead of a technical interview where you have to write code manually, most likely you’ll be given a workstation with an IDE and computer access and asked to implement so-and-so program. Some of the more progressive ones will do a pairing exam where you have to do pair programming with one of their existing developers; such pairing exams give insight on two fronts: your technical skill and how well you can work well with someone already on the team you’re applying for
I kind of prefer the old style of recruitment processes because they give a better chance for people like me who had minimal formal programming education but can learn easily and quickly
“Do you know what’s there, waiting beyond that beach? Immortality! Take it! It’s yours!” – Achilles, Troy
Each person has a different view of what their life’s purpose is, but I’ve found more often than not it relates to some form of immortality. Usually that means leaving something behind, some trace of yourself so that the world remembers you, something that says “I was here, I existed.” For many people that means offspring, for others it may mean some other legacy: children taught, people helped, ideas expounded, inventions created, companies founded, and so on
For me, I wouldn’t mind actual immortality. Who knows, it may still happen in our lifetime. Medical science may yet find a way to extend our lifespans or even permanently remove aging (at which point we really need to expand beyond this planet). Or maybe we manage to survive until the singularity and live on as artificial constructs
Literature and popular culture often portray immortality as some sort of curse. Sometimes a literal curse, as in vampires or highlanders needing to cut each other’s heads off. More often the implied of curse of eternal solitude – Superman is often taunted by writers with the idea that everyone he loves will eventually grow old and die, and other immortals are often portrayed as not wanting to burden themselves with short-lived human connections
What interests me the most about the idea of immortality is the idea that we as a species have so much to look forward to. (Assuming we manage to bypass The Great Filter and avoid screwing things up for ourselves of course.) Even just the coming decades hold a lot of promise, with advances in space exploration, artificial intelligence, autonomous vehicles, and so on that may very well expand the horizons of the human experience. And who knows, immortality may actually help George R.R. Martin finish the Song of Ice and Fire series!
I want to be immortal if only to be able to see where we are going and what comes next. The future, it comes. Perhaps sooner than many of us expect
I once had to advise someone who found himself irritated at receiving lots of comments during code review. I think my response was good enough to quote verbatim:
This problem arises because you are too attached to your code. Your ego is associated with the code you write and you feel that any comments or defects found reflect upon you as a person.
You are not perfect. You will not write perfect software, and that’s fine. It’s not a flaw, it’s just the way software is. It isn’t written all in one go, magically perfect and elegant and satisfying all the requirements. Good software goes through multiple iterations and many eyes looking at it.
It is also important to treat it as a learning experience – learn what you can from each code review comment and try to apply what you learn to future code you write. This also helps you minimize review comments in the future. Instead of treating the large number of comments as a shortcoming on your part, treat it as a metric you can improve upon.
It’s probably true of any endeavor which results in creation – be it programming, arts, crafts or whatnot – that you need to be able to divorce yourself from your work so that you can accept and analyze and learn from criticisms objectively and without feeling terrible about yourself.
Fun fact: All programmers write terrible code. Yes, even the veterans, the rock stars, the elite, they have all written terrible code at some point in their careers and they will probably write more terrible code in the future. The key is to recognize those instances – either through introspection or being open to criticism – and learning from them and trying to minimize them in the future. Or at least correct them earlier!
I am of course a long-time Magic the Gathering player. Over the past year or so I’ve also been playing Blizzard’s digital CCG Hearthstone (limiting myself to free to play since who has money to spend on two CCGs?) and I’ve been thinking about the design parallels and differences between the two. If you’re a Hearthstone player, you’ve probably read a lot of these things before, since many well-known pros play both MTG and HS. This is written more towards the Magic player in mind to get to know Hearthstone.
Mana system and Mulligans
Like most modern successors to MTG, HS does away with the concept of “mana screw” by automatically providing one generic mana to each player per turn. It’s really MTG’s big weakness and what turns off many players. MTG Head Designer MaRo tries to justify the existence of mana screw here. HS’s mana system is much simpler, and has no concept of colors or mana screw or color screw. One disadvantage of this is that all costs are the same, and they have to restrict deck access to cards via another method – class-specific cards. This makes it impossible to have the equivalent of a “multicolor deck” like in Magic, which means there are theoretically fewer possible deck archetypes in HS for a comparable set of cards.
I’m a fan of Hearthstone’s mulligan system – selectively sending back particular cards from your opening hand – as opposed to Magic’s sending back the entire hand. Unfortunately, Magic is already balanced around the current mulligan system, and it will probably have issues if you only have one chance to mulligan and still draw no lands.
Hearthstone is definitely a more limited game than Magic because it follows one important rule: you can’t interact during your opponent’s turn. This has the benefit of streamlining matches and making them go faster (no need for concepts like the stack and priority from MTG) , which is important for a game played online. The disadvantage is a greatly reduced design space which HS has to compensate with in other areas.
There are some other limitations to streamline/simplify gameplay:
No graveyard (well, HS has a concept of “minions that died this turn” or “minions that died this game”, but there is no visible graveyard zone). This means Magic’s graveyard-based mechanics such as Flashback or Unearth can’t be translated to Hearthstone
No manual searching through the deck. When an effect pulls something out of the deck, it’s always random
At most 7 minions (creatures) on the board on each side
Strengths of the Digital Format
Despite the above limitation, HS does earn some additional design space since it takes advantage of the exclusively digital format in a number of ways not available to Magic, such as:
Damage to minions not healed at EOT – in Magic, this would not have been practical since it’s a lot of effort for players to track the damage to individual creatures. For a digital game it’s easy since it can be done automatically. This also provides some mechanics that can’t usefully translate to MTG: the Enrage mechanic and effects like “Draw a card for each damanged minion”
Effects can generate new cards – both spells and minions. Magic can do this too, through the use of “tokens” (but only for permanents, not spells). Magic’s tokens however are “second-class” permanents since they are not real cards. In HS, the generated cards are real cards that can be returned to hand, shuffled into your deck, etc. Furthermore, the generated cards can be either existing cards (whether you have them in your deck or not – Discover mechanic or effects like Piloted Shredder) or cards that are not even available for deckbuilding such as the Spare Parts generated by some mechs
More randomly generated elements – Magic has some RNG too, but not nearly as much as HS. I believe that in both games, serious competitive players don’t like too much RNG.
Effects can permanently boost cards not in play – this includes effects like “all cards in your deck get +1/+1” or “reduce the cost of this card for each turn it is in your hand”. This is possible since we can trust the game engine to correctly process and track hidden information
Board position matters – minions can grant bonuses to adjacent minions, or effects can target the leftmost minion, etc. Actually, Magic can do this too, but given that they’ve moved away from “graveyard order matters” because it places too much effort on the player, I suspect they are not likely to do this for similar reasons
Easily balance existing cards – Blizzard hasn’t done it too often, but they do issue nerfs to cards that are too powerful. Before the introduction of the Standard format they even nerfed some core cards to free up future design space. In Magic they try to avoid functional errata because they have no way of ensuring the ifnromation is propagated to all owners of previous printings of the same card
Hero Power – each hero has a power that costs 2 mana. The great thing about this it reduces the effect of “cost screw”, i.e. drawing high cost cards early, since your hero will always have a low-cost play available no matter what. There’s also some design space there they started using in earnest with The Grand Tournament expansion, such as the Inspire mechanic or effects that modify hero powers.
Secrets – to compensate for not being able to interact during the opponent’s turn, some classes have access to secrets – these are spells that generate effects during your opponent’s turn, based on particular triggers. The opposing player wouldn’t know
Taunt – the equivalent of Taunt in MTG is “Blocking”. Since you cannot do anything on your opponent’s turns, blocking the same way as MTG is impossible, so they have this mechanic to replace it. Currently, HS has no way for minions to bypass Taunt without removing the Taunt minion itself – there are no evasion mechanics.
Charge – the equivalent of MTG’s Haste. However, it is stronger here in HS since your opponent cannot interact during your turn. This means Charge creatures essentially get a free attack unopposed and can throw off your opponent’s combat math. This makes effects that grant Charge particularly strong. An example was the infamous nerf to Warsong Commander because granting Charge to other creatures enabled one-turn kills.
Divine Shield – no equivalent in MTG, but I think something can be worked out if needed. Something like:
Divine Shield (This creature enters the battlefield with a divinity counter on it. Whenever it takes damage and has a divinity counter instead remove a divinity counter.)
I’m actually a big fan of Divine Shield as a mechanic, it’s more interesting and a lot simpler than Magic’s defensive mechanics Protection or Regeneration
Windfury – this is basically the same as Magic’s Double Strike, except Magic is limited by the rules to two strikes, while HS has one card that has Mega-Windfury, allowing four strikes
Overload – this is HS putting its’ simpler mana system to good use. Overload allows you to “borrow” mana from the future to reduce the costs of your cards. The downside is you have less mana available next turn. The closest equivalent is probably Magic’s Echo mechanic or the “Pact” mechanic from the Pact of Negation cycle, although neither are exactly the same
Combo – this is the Rogue mechanic in HS, it grants an additional effect if at least one other card has been played in the same turn. This is easily implementable in Magic:
Eviscerate 1R Sorcery Eviscerate deals 2 damage to target creature or player. Combo – Eviscerate deals 4 damage instead
It’s no different than Magic’s other “enhancing” ability words like Morbid or Kicker which grant additional effects depending on certain conditions
Stealth – this is the same as Magic’s Hexproof, except Stealth wears off once the minion attacks, and stealthed minions can’t be attacked. The usage is generally the same – to protect your minion until it can actually gain you some value.
Battlecry and Deathrattle – in Magic, these are simply triggered abilities “when the creature enters the battlefield” and “when the creature dies”. If these were named keywords in MTG, it would open up some additional design space that HS already uses. MTG does use this design space sometimes, but the templating is difficult, see Torpor Orb. More complicated abilities like “Battlecry: Trigger another minion’s Deathrattle effect” would not be worth the effort to implement in MTG unless similar keywords are defined to make templating easier.
Spell Damage – this mechanic increases the damage dealt by burn spells. In Magic, such spells are almost exclusively red spells, so I’m not sure how likely it would be to keyworded in Magic. This design space has been used in MTG on occasion, but it’s mostly damage doubling instead of incrementing.
Choose One – I actually wasn’t aware this was a named mechanic until they took advantage of it with Fandral Staghelm. Magic’s modal mechanic has never been used in such a way, but imagine an effect like “Whenever you make a choice for a modal ability, you may choose one additional mode” – makes your Cryptic Commands way more awesome!
Silence – this is basically “remove all abilities” in Magic. To be truly equivalent, it should also remove power/toughness boosts and auras attached to the creature. Seems perfectly doable in Magic, although it might have memory issues, unless it’s as an aura.
Freeze – frozen minions can’t attack the next turn. It’s mechanically and thematically similar to tapping effects often found in blue and white cards. Freeze effects in HS can easily be replicated in Magic. The main difference is that frozen Taunts in HS can still “block” so Freeze can’t be used offensively to get rid of the “blockers”
Hearthstone is a pretty young game compared to Magic, but as far as I can tell it’s doing pretty well. It provides a fun, streamlined experience and takes advantage of the strengths of the digital format to overcome the weaknesses brought about by the streamlining. The monetization model is friendly enough that even cheap f2p players like me can appreciate it. So far Magic hasn’t had a real competitor in the paper space, but HS is a serious competitor in the digital space since it makes MTG’s digital offerings look terrible by comparison. Hopefully both games can learn more from each other and grow more in the future.