Christmas
December 22nd, 2008Between the family, the spectacular amount of good food, ad the time I get to spend with Kristen- Well, while I technically might not be a “Christian” in any way shape or form, I sure do enjoy Christmas.
Between the family, the spectacular amount of good food, ad the time I get to spend with Kristen- Well, while I technically might not be a “Christian” in any way shape or form, I sure do enjoy Christmas.
I was browsing reddit (like always) and someone pointed out that- while many low-level courses require you to program in Java, very few of them explain the well-known preamble of public static void main(String[] args).
So, let’s see what I can explain – anybody who’s not interested in programming, or good at programming, or who already knows – can tune out now.
You’re going to have to be patient with my Java code. I try to avoid Java as much as possible in favour of languages like Python, so my Java’s a tad rusty.
Before we talk about ‘public’ and ’static’, let’s throw out a quick Object-Oriented-Programming refresher.
Imagine that you’re writing a program that deals with a lot of data. You’re managing 200 employees, and you’re writing a program to schedule vacation time for each one of them. The first thing that many programmers will think about is how to deal with employee data.
In this case, we’re going to need to keep track of – at the very least- employee names and vacation times. For each employee, we can maintain the employee name as a simple string- and the employee vacation time can be represented as an Vector of TimeSpan objects. I’ll explain that Vector/TimeSpan thing in a second.
So, let’s tie that data together: a string (to hold the name) and a Vector (to hold the dates). We’ll do that with an Employee class.
import java.util.Vector;
class Employee {
string name;
Vector vacationTime;
}
Before we continue, let’s talk about the Vector and TimeSpan classes…
A TimeSpan is an class representing a chunk of time. For example, if I wanted to take January 10-13 off from work, I could represent it within the system as…
// Remember to properly import TimeSpan and Date // Note that all of this easily-understood year-month-day stuff has been 'deprecated' // by some harder-to-understand "Calendar" stuff in newer versions of Java. Date startDate = new Date(2008, 1, 10); Date endDate = new Date(2008, 1, 13); TimeSpan timeoff = new TimeSpan( startDate, endDate );
We can’t be sure how many different vacation ’spans’ an employee might have. Mr. Baker from Accounting might use his vacation days sparingly to turn long weekends into four or five-day weekends all year round, while Mr. Asher from the Hat Department might blow all of his vacation days in one four-week-long trip to Spain. Given that, we have no clue how many TimeSpan objects we’re going to have to store!
Fortunately, the Vector class exists- you can think of a Vector as a collection of ‘things’ that you can add to or remove from at will. An array where you don’t have to specify the size beforehand.
Here’s a Vector tutorial as an introduction.
Okay, so now we have an Employee class. Let’s try it out, shall we?
// Here I create an employee- and give him Christmas Vacation off. Employee me = new Employee(); Date startChristmasVacation = new Date( 2007, 12, 22 ); Date endChristmasVacation = new Date( 2007, 12, 26 ); TimeSpan christmasVacation = new TimeSpan( startChristmasVacation, endChristmasVacation ); me.name = "Curtis Lassam" me.vacationTime = new Vector(); me.vacationTime.addElement( christmasVacation );
Wonderful. Now, let’s say that we want to count all of the vacation days an employee has in a year. We could write some code to handle this for us- it will loop around, counting the number of days in each TimeSpan.
// note: this is one way to trawl through a Vector,
// although you can do a standard
// for ( int i = 0; i < me.vacationTime.size(); i++)
// loop, instead, if you want.
int days = 0;
for (Enumeration e = me.vacationTime.elements(); e.hasMoreElements();)
{
TimeSpan vacation = (TimeSpan) e.nextElement();
int ms_per_day = 86400000; // number of milliseconds in a day.
days += math.floor( vacation.getEndDate().getTime() - vacation.getStartDate().getTime() / ms_per_day );
}
It's a tad ugly, but it does the job. We may talk again later about that 86400000- just plunking 86400000 down there in the middle of the code? That would be ugly. It's referred to in programming as a "magic number", and considered bad form. We're at least naming it, though.
So, we've got this handy function to tally up the number of days - but what if we want to do it more than just the once? We have to copy and paste the code all over the place. Not cool. Those of you in the audience with some experience know that this belongs in a function.
Now, being as this function is designed to work on a Vector of TimeSpan objects, we can be pretty sure we're only ever going to be using it on the Employee. So let's include the function in the Employee class.
class Employee {
string name;
Vector vacationTime;
public int getNumberOfVacationDays()
{
int days = 0;
for (Enumeration e = vacationTime.elements(); self.hasMoreElements();)
{
TimeSpan vacation = (TimeSpan) e.nextElement();
int ms_per_day = 86400000; // number of milliseconds in a day.
days += math.floor( vacation.getEndDate().getTime() - vacation.getStartDate().getTime() / ms_per_day );
}
return days;
}
}
One thing you'll notice is that the 'getNumberOfVacationDays()' function refers to 'vacationTime'- but it's not included as an argument to the function! In this case, the 'vacationTime' refers to the 'vacationTime' of whatever class called the 'getNumberOfVacationDays()' function.
Employee me = new Employee(); Employee ted = new Employee(); Date startChristmasVacation = new Date( 2007, 12, 22 ); Date endChristmasVacation = new Date( 2007, 12, 26 ); TimeSpan christmasVacation = new TimeSpan( startChristmasVacation, endChristmasVacation ); me.name = "Curtis Lassam"; me.vacationTime = new Vector(); me.vacationTime.addElement( christmasVacation ); ted.name = "Ted Koppel"; ted.vacationTime = new Vector(); ted.vacationTime.addElement( christmasVacation ); System.out.print( "My Vacation Days: " + me.getNumberOfVacationDays() + "n"); System.out.print( "Ted's Vacation Days: " + ted.getNumberOfVacationDays() + "n");
In that case, the first time 'getNumberOfVacationDays()' is run, me.getNumberOfVacationDays() uses me.vacationTime. The second time, ted.getNumberOfVacationDays() uses ted.vacationTime.
One thing that's a bit of a pain- before we put any values in the Employee 'vacationTime' bin, we need to instantiate the variable with ted.vacationTime = new Vector(); Ideally, this would happen automatically, every time we create a new Employee.
What we need here is a constructor- a function that runs automatically whenever 'new Employee()' is called.
Constructors have special syntax in Java. They have no return value, and always have the same name as the class. Constructors exist, with varied syntax, in just about every language that supports OOP.
class Employee {
string name;
Vector vacationTime;
public Employee()
{
vacationTime = new Vector();
name = "NAMELESS EMPLOYEE";
}
public int getNumberOfVacationDays()
{...}
}
Of course, the code I've written - aside from being untested in any actual Java interpreter - is wrong for a number of reasons. One important way this code can break is that- if an employee has two overlapping breaks, 'getNumberOfVacationDays()' will overreport the number of vacation days that the employee truly has. As an example, if I have January 23rd through January 29th off, and I also claim to have January 21st through January 28th off, the system will claim that I have 15 days off, instead of 9 days off. Let's imagine a function, 'overlapCheck()', that runs through the class's vacationTime vector and combines any overlapping TimeSpans.
Our employee class now looks like this:
class Employee {
string name;
Vector vacationTime;
public Employee()
{...}
public int getNumberOfVacationDays()
{...}
public void overlapCheck()
{...}
}
The overlapCheck() function just operates on data internal to the class- it doesn't take any arguments or return any values.
To be safe when running our program, we'd have to run 'overlapCheck()' every single time we add a new TimeSpan to the vacationTime vector. What a pain!
Okay, let's create a function to automatically run overlapCheck() whenever a new TimeSpan is added to the Employee's vacationTime.
public void addVacation( TimeSpan vacation)
{
vacationTime.addElement(vacation);
overlapCheck();
}
There we go- now every time we add a TimeSpan to an Employee's vacationTime, it'll check if it overlaps with any other TimeSpan and merge any combined time.
Unfortunately, though, now we have to go back and change all of the rest of our code- replacing me.vacationTime.addElement(christmasVacation) with me.addVacation(christmasVacation) anywhere vacationTime.addElement exists. While this is trivially easy in our simple example, it would be much more difficult if our Employee code was used in a lot of other places.
It would have been a lot easier if we had just written 'addElement' when we had first written the Employee class. It would be an almost empty function, just ...
public void addVacation( TimeSpan vacation)
{
vacationTime.addElement(vacation);
}
... but if we wanted to change it, we'd end up saving ourselves a lot of time. In fact, we could do the same things with most of the different actions we can perform on the Employee. Let's start with the employee's name. Instead of working directly with me.name, we should write a getName() function- that returns the name - and setName() function - that takes a name as input, and assigns the name to the employee.
Here's an example:
class Employee
{
public string name;
...
public string getName() { return name; }
public void setName( string name ) { this.name = name; }
}
Then, if we want to perform any validation or automatic actions when a name is added for an employee, we just need to alter setName().
As an example, maybe we've decided to start keeping a firstName and a lastName field for each employee, instead of just a name field. If we had written a setName function (a setter), we could just switch it around as follows:
// This is the old way
public void setName( string full_name )
{
name = full_name;
}
public void setName( string full_name )
{
// Note that this will break if the 'full_name' contains a middle name.
// "Curtis James Lassam" would register as firstName = "Curtis", lastName = "James"
firstName = full_name.split(" ")[0];
lastName = full_name.split(" ")[1];
}
That's a lot easier than changing the code everywhere the name is involved. This is why it's considered 'good practice' to build your classes with ample getters and setters.
Of course, now that we've built a getName and setName function, it's entirely unnecessary- and potentially dangerous- for us to directly access the Employee's 'name' variable. For all he knows, it might disappear entirely!
What do we do to protect ourselves from this eventuality? We make the 'name' variable private. This means that it can be accessed by functions within the Employee class, but not accessed by functions outside of the Employee class.
You can also specify that a variable is public. A 'public' variable is... well, just a normal class variable, like the ones above.
As an example...
class Pirate
{
public string name;
private int stolen_booty_value;
public Pirate(string name, int stolen_booty_value)
{
this.name = name;
this.stolen_booty_value = stolen_booty_value;
}
public int getBootyValue()
{
return stolen_booty_value;
}
}
Pirate blackbeard = new Pirate("Edward Teach", 5000);
System.out.print(blackbeard.name); // prints "Edward Teach"
System.out.print(blackbeard.stolen_booty_value); // throws an error
System.out.print(blackbeard.getBootyValue() ); // prints "5000"
Okay, let's talk about another reason why we might want to hide something using the 'private' modifier. It's not that often that we write an entire codebase ourselves. More frequently, we're working on teams, and other people are going to be using the classes that we write.
Certain elements of classes are important to the class, but entirely unimportant to the programmer using the class. For example, once we've implemented the automatic overlapCheck() in our Employee class, the person using the Employee class doesn't have to think about it at all anymore. He shouldn't have to think about it. In this case, we make the overlapCheck() function private. While it exists, the programmer can't see it or call it.
Of course, most of the time, when we're writing a function in a class, we want it to be public, not private.
Wow, it took a long time to explain public. The rest of the article should take a bit less time. On to... static!.
Remember way back when we wrote the getNumberOfVacationDays() function? We defined a constant ms_per_day- the number of milliseconds in a day- in order to perform the calculation.
But, inefficiently enough, every single time we run 'getNumberOfVacationDays()', the computer is going to create a ms_per_day variable, and fill it with the value 86400000. That right there is a waste of time and effort.
Instead, we could define ms_per_day as a member of the class- a private member, of course, because nobody needs to know that it's there, and we certainly don't want anybody changing it.
class Employee
{
private string firstName;
private string lastName;
private Vector vacationTime;
private string ms_per_day;
public Employee()
{
vacationTime = new Vector();
name = "NAMELESS EMPLOYEE";
ms_per_day = 86400000;
}
}
Once again, however, this is not the right answer. In this solution, we have ms_per_day defined once for each employee. If you think about it, ms_per_day is the same for ALL employees- the number of milliseconds in a day doesn't ever change, really.
So, what we do is make the ms_per_day variable static. What this means is that there's exactly one, shared copy of the ms_per_day variable, no matter how many times the class is created.
class Employee
{
private string firstName;
private string lastName;
private Vector vacationTime;
private static ms_per_day = 84600000;
public Employee()
{
vacationTime = new Vector();
name = "NAMELESS EMPLOYEE";
}
}
The static variable for functions works much the same way. Imagine that you've created a useful function that goes along with a class- but one that doesn't require any data from class members.
Let's say that you want to display a vacation (TimeSpan) in a specific way- let's say, "May 2, 2008 to May 5, 2008" You can write the function as part of the class, like so:
class Employee
{
private static DateFormat date_formatter = DateFormat.getDateInstance( DateFormat.MEDIUM );
...
public string formatTimeSpan(TimeSpan span)
{
string startDate = date_formatter.format( span.getStartDate() );
string endDate = date_formatter.format( span.getEndDate() );
return startDate + " to " + endDate;
}
}
But- if you think about it- the formatTimeSpan() function doesn't depend on any of the variables inside the Employee class. If you have a TimeSpan you want to format, you must create at least one Employee class with which to format it- like so:
Employee someguy = new Employee(); System.out.print( someguy.formatTimeSpan(christmasVacation) );
That's a bit strange- why go to all of the trouble of instantiating 'someguy'? You're not planning on using him.
Instead, we can make the formatTimeSpan function a static function.
class Employee
{
public static string formatTimeSpan(TimeSpan span)
{...}
}
That means that formatTimeSpan is just a disconnected function- it's not tied to any specific class data. You can call static functions without creating a class- like so:
Employee.formatTimeSpan(christmasVacation);
You can call static class variables the same way-
// this would get the 'ms_per_day' variable we were talking about earlier. // except that 'ms_per_day' is private, so this will fail. Employee.ms_per_day;
Java functions must specify their return value- if I wanted to create a function that added two integers, I would have to specify an 'int' return value, for example.
public int add(int one, int two)
{
return one + two;
}
void is the type given to functions that don't return any value at all.
This one is simple. When you run a Java console program, it looks for the 'main' function in your chosen class, and runs that function.
Let's briefly talk about The Command Line.
Many new programmers have been raised in a world of Graphical User Interfaces. All of their time is spent in Windows, and when they program, they program in an Integrated Development Environment like Visual Studio, or IDLE, or Eclipse.
Many people don't even know about The Holy Command Line, the One True Interface. Neal Stephenson wrote a long article about it, and (despite it's length), You Should Read It. I promise you- it's worth it. I may even acquire the paperback version. It's a .txt file, so worst-comes-to-worst, you can load it on to your iPod and read it on the bus.
Want to see a command line? You need to open a console. In Windows, go to the Start menu, find run, and type in cmd. On a Macintosh computer, hunt around in the Applications folder for Utilities, where you'll find a program called Terminal.
It doesn't seem like much- a prompt, a blinking cursor, just staring at you.
From the command line, however, you can do just about anything that you could do from the Graphical User Interface.
Now, I'm not going to show you how to use a command line. Just trust me that you are going to have to learn. It may seem esoteric, but it's a fundamental programming skill.
Windows XP and Vista have DOS-based command lines, and... well... they're just terrible to work with.
Thanks to the fact that Mac OS X is based - through a long and arduous, albeit interesting history - on BSD Unix, it has an advanced command-line interface with many useful features.
The many Linux distributions are designed in such a way that you can run the whole system from the command-line if you want, entirely graphics-free - and, in fact, if you want to really get a feel for the ol' command-line, I recommend you install and configure a Slackware box from scratch. It'll be a learning experience, I promise. (I do it every couple of months or so, but I always chicken out and end up working with Mac-Os X again in a few days- but I do keep a VM of Ubuntu Server Ed. running on my computer at all times, so I'm not entirely a duffer. )
Why is the command line so popular with programmers, and so relatively unknown by everyone else? Why, it's simple, cap'n. Command line programs are much, much easier to program. Putting something together with a snazzy visual interface- even a tiny little program- will probably take you the better part of a day to get right. A command-line program is the sort of thing you can toss together in minutes.
Command-line programs are usually free, and often very powerful. With 'gpg', you can manage strong cryptography, with 'git' you can manage a huge shared codebase, and with 'gcc' you can compile C programs. With 'grep', you can search for just about anything. ("G" is a popular letter. It usually stands for "GNU" but not always.)
Command-line programs can be tied together and automated in ways that graphical programs just can't- Often, you can pipe the output of one program right into the input of another.
Here's an example of a simple (Mac OS X) command-line program in action:
I hear that you're coming to the party on Thursday.
That's awesome.
I hope you bring Nachos.
If you don't, Lorin's going to do that thing with your head again.
He really loves the Nachos.
The "cd" program takes "/Users/curtis/Documents" as an argument, and changes the current directory to "/Users/curtis/Documents". The cat program takes "message.txt" as an argument, opens "message.txt" if it exists, and prints out the contents of "message.txt".
See, command-line programs work almost exactly like functions. They take arguments, and produce output.
When you write a 'console' program- in Eclipse or Visual Studio- what you're writing is a command line program. It takes input, or 'arguments', and produces output. That's just about all you write in University. If you were to run one of your Java programs, the way that it was intended to be run (that is, without the huge IDE), you'd open a command-line and go ...
So, the string[] args part of your standard Java program is... a string array of all of the arguments passed to the program.
Let's create a sample program. Echo.
class Echo
{
public static void main( string[] args)
{
for(int i = 0; i < args.length; i++ )
{
System.out.print( args[i] + " ");
}
}
}
When we run the program, it will just return all of the arguments that it was originally passed.
So... in conclusion... class Foo { public static void main( string[] args ) { } } means:
(Xianny) Eyebrows, the chubby rogue, (Curtis) Richard, the mage who is also a chef, and (Marcel) The Generic Dwarf, made amends- having forgotten the violent events of last day. The inn that they occupied had also attracted (Kristen) Athena, the somewhat-spacey cleric. She described herself as ‘normal’ and agreed to help with the Kobold problem that everybody was having.
On the road to the Kobold’s lair, the party of four encountered… Kobolds! (surprise!) Having a cleric on the team proved to be a significant step forward, and the Kobolds were summarily dispatched. Eyebrows started to get a feel for the hunt- learning that her sneaky hits from behind did a lot more damage. Spirits were high. The party found a dark little figurine in the hands of one of the Kobolds. Richard successfully identified it as a fetish of Orcus, dark god.
Travelling forward, the team found… more Kobolds! This time, a whole awful lot of Kobolds in a forest. Generic Dwarf managed to shake off several javelins to the important bits. The team worked together and once again made mincemeat of the forest-ful of Kobolds. One of the Kobolds managed to dash off, yelling “Irontooth must be warned!”. How ominous.
The party followed the escaped Kobold into the most Kobold-ful spot yet- a cave, containing Kobolds of all stripe- as well as an axe-wielding goblin with a rather spectacular amount of hit-points.
One well-placed fire-spell managed to clear the caves of 8 of the Kobolds- after which Richard cracked his knuckles and tossed off a pithy comment. Another 2 Kobolds were knocked clean unconscious by a spell of Sleep, leaving only the axe-wielding super-goblin, a Kobold priest, a Kobold skirmisher and a Kobold minion.
The cleric, however, foolishly ran to the front lines, putting her in a position where the remainder of the Kobold forces could concentrate their attacks on her. She fell unconscious. After taking a near-fatal series of blows from the axe-wielding goblin, the Generic Dwarf attempted (and succeeded) first aid on the cleric.
Between the two of them, they managed to stay alive a bit longer in battle, but in the fray the axe-swinging goblin took Eyebrows’ head clean off. In one blow, she went from a healthy albeit battered rogue to a pile of relatively useless meat.
The onslaught proved to be too much- the Dwarf fell, and Athena- unable to heal him any further- instead just decided that an expeditious retreat was in order. “Book it!”, yelled Richard as they made haste for the woods. Again.
Things seemed bad for Generic Dwarf, but luck was in his favour and he rose. Surprising the goblin, he succeeded at an intimidate check (one assumes, yelling “DWAAAARF!”) shocking the goblin enough so that he could nab Eyebrows’ dead body and leave.
Athena arrived at Winterhaven first, and retired to the pub for a nice ale.
The Dwarf and Richard arrived next, quibbling about what to do with the dead body of Eyebrows. While Generic Dwarf favoured rescuing her, Richard argued that the going price for such a resurrection was 500 gold pieces- not a paltry sum, and clearly out of the price range of the team. Richard suggested instead that they dump the body in a nearby creek and attempt to find a new hero willing to join the team. (Note to the DM: If you feel that it’s more appropriate for Richard to be Unaligned instead of Good at this point, I wouldn’t resist it any.)
To make his point, Richard suggested that resurrections don’t just grow on trees, idly tapping the battered lump that was Eyebrows’ corpse with the Orcus figurine that he had earlier acquired. In retrospect, not the greatest idea. Eyebrows’ corpse started shambling up with a new, dark life. Richard shrieked like a little girl (“ZOMBIES!”) and paced away, leaving the Generic Dwarf to deal with the zombie Eyebrows.
Generic Dwarf mistakenly thought that Eyebrows had come back to life, and attempted first aid- only to be slammed by the undead’s fury. At this point, Richard had regained his composure and froze the zombie from a safe distance.
Well, at least the body disposal problem had been solved.
I’d like to take this opportunity to point out that our team’s Rogues are having a definite Spinal Tap Drummer problem.
Although the band arguably had 32 drummers during its history, these are the six that are mentioned by name:
- John “Stumpy” Pepys (1943-1969) Cause of death: Gardening accident.
- Eric “Stumpy Joe” Childs (1945-1974) Cause of death: Choked on vomit, although it was never determined whose vomit it was.
- Peter “James” Bond (1949-1977) Cause of death: Spontaneous combustion
- Mick Shrimpton (1948-1982) Cause of death: On-stage explosion.
- Joe “Mama” Besser (19??-1983) Cause of death: Missing, presumed dead, or playing jazz.
- Richard “Ric” Shrimpton (1948-?) Cause of death: No one knows what happened to Ric. None of the band members thought to ask each other. We’ve also heard that he sold his dialysis machine for drugs, and we assumed he died.
“Geek Humour” articles feature jokes that are only funny for complete and utter nerds. You know, like me.
My favourite beverage ever is now the Recursive Tom Collins.
Thanks, XKCDB!
They actually gave me a Chick tract! OMG!
Throughout my life, I’ve used bad humour to punctuate just about anything that I do. I’m not exactly Mitch Hedberg (or even Carlos Mencia – ugh), but I’m just witty enough to get a hit every couple of tries.
Not just that, I do it all the time. During class, during finals, in Very Serious University Reports, at work, in the boudoir, all the time. Wherever I go, people gradually either decide that I’m hilarious (if they get it) or incredibly strange (if they don’t).
This also means that I get the “appropriateness” talk a lot. Like, at least thrice a year, ever since I was in Grade 4 or 5 and started this sort of thing. I’ve been passed over for some jobs, almost fired from some others, lost marks here and there, but most of all, I get the “appropriateness” talk.
The “appropriateness” talk is a universal constant. It often starts with something along the lines of ‘did you think that we wouldn’t notice?’- Which, of course, I usually nod negatively to. Of course I expected them to read these inappropriate things that I wrote- otherwise to what purpose would I write them?
After that, they’re either a Type A- we’ll call it the Fuddy Duddy- or a Type B- the Coward. The Type A will tell me that the thing that I wrote is directly inappropriate, and not to do it again. The Type B will invoke the potential specter of the Type A- “Some other people might find this inappropriate, so you should be careful about that sort of thing.”
The Type B (Coward) is occasionally a free-spirit who has been crushed by a Type A (Fuddy Duddy)- who then starts believing (falsely) that everybody is a Fuddy Duddy as well. Occasionally, however, the Coward is a Fuddy Duddy in denial or disguise- invoking a straw-man Fuddy Duddy to further their Type-A arguments.
It’s this same mentality that makes Political Correctness and Business Casual the norm- one Type A (Fuddy Duddy) can spawn many Type B (Cowards), and the Fuddy Duddy can then disguise himself as one of the Cowards.
You’ll find, however, that many people enjoy a dash of inappropriate humour with their day-to-day reading. Injecting it into boring project documentation can make it more fun to write and read. Writing a test is a horrifying experience, and marking is a painful chore- a creative answer can really perk things up.
I’ve also found that such inappropriate humour usually ends with one of five different outcomes – here I’m using academia as an example, but it’s the same for work environments:
Given these outcomes, and the surprisingly low number of *actual* Type A’s, I’ve recieved the Type B speech far, far more often than I’ve ever faced any sort of actual consequences for my actions.
On top of that, the consequences are rarely more than a slap on the wrist- a small price for being my usual distinctive self. As a cherry on top, the fifth occurrence, “Bonus Marks”, while rare, is nice, and seems to actually get more frequent as I get older and (I assume) more people are sucked into the Type B trap of professionalism.
Of course, it can go too far- I still have to complete all of the required work. Humour shouldn’t be a way to avoid the task at hand- just a distinctive flair.
With all of the risks associated, you might ask- why do I do it? Why do I put myself out there? A bad joke on a cover letter will disqualify me from more jobs than it will qualify me for.
It’s simple- if people don’t like it, they’re not going to like me, and I’m probably not a good fit for their company. Any environment that doesn’t appreciate the bad humour- I’m probably not going to be happy there. That’s why I’ve started doing it right on my cover letter. The company that reads a bad joke of mine and goes ‘this guy… I like this guy!’… well, chances are, that is the company that I wanted to work for all along.
A quick summary of the happenings, for those people who weren’t there:
(Angelina) Leukemia, the brave rogue, (Xianny) Eyebrows, the sneaky rogue, (Curtis) Richard, the mage who is also a chef, and (Marcel) The Generic Dwarf, met under mysterious circumstances, ostensibly because they were all seeking fame, fortune, gold, and adventure.
Immediately on their path, they encountered an unfortunate series of Kobolds. The Generic Dwarf stood in the centre of their assault, soaking up damage and occasionally felling a gnome. In his capacity as damage-soaker, his beard was soaked in both napalm and acid. The two rogues popped in and out, dealing minor damage, and Richard felled Kobolds by the handful with his powerful burst attacks. Eventually, the last kobold was felled, minced, and served in a stew that was (everyone noticed) quite delicious.
The characters found themselves upon a small settlement- Winterhaven. While the rest of the team conferred about whether or not the city was safe, Richard merrily waved at the town guard, who waved back. Seems safe enough. The party walked into the town’s tavern and bought a few pitchers of ale. At this time actual beer was brought out (Thanks, Marcel!) and consumed. It was both cool and refreshing.
After a bit of snooping. it was found out that the town of Winterhaven had a tad of a Kobold problem. (Yuh, really?) And if the team would be so kind as to clear out the Kobold’s nest, there would be mad cash in it for them. (Okay, 100 gold pieces and a bottle of fine wine. )
Setting off on the road, the team encountered their second set of Kobolds for the day. The Generic Dwarf went back to taking loads of damage, taking hit upon hit and eventually deciding that it would be prudent to flee. Richard commented that this makes him the “Worst Dwarf Ever”. Without a thick damage soaker to take the front, the brave rogue immediately took a felling blow. In a halfhearted rescue attempt, Richard flooded the battlefield with thunder-wave upon thunder-wave. The Kobolds were severely hurt, but sadly, Leukemia didn’t survive. With naught but a few hit points, a cowardly Dwarf, and sneaky, sneaky Eyebrows, Richard thought that an expeditious retreat was in order.
Richard dashed away, yelling “CHEESE IT!” and leaving Eyebrows the Rogue to his own devices. Eyebrows was knocked unconscious by the Kobolds, and Generic Dwarf and Richard booked it back to Winterhaven.
Upon reaching Winterhaven, Richard and Generic Dwarf stopped to catch their breath, only to encounter an infurated Eyebrows. He attempted to greet them, knife concealed in his palm, but Richard noticed and immediately bellowed “GUARDS!”.
Richard tensed, Generic Dwarf grabbed his Generic Dwarven Weapon, the guards.. guarded… and the session ended, to be picked up next day.
And now for… D&D Tips!:
the same goes for advance payment – especially if you’re a group of shyster-looking unproven heroes. Maybe if you’re super lucky you’ll be able to finagle a few extra coins. If you’re lucky.