Wednesday, July 22, 2015

Your Bug Reports Suck

Introduction

I've been a professional software developer for nearly a decade. In that time, I've read a lot of bug reports, and almost all of them have sucked. A lot. Hardcore suckitude. They really, really suck.

There's something you need to understand about us developers: We typically don't know how to use the software that well. That might come as a shock, but it's true. The people who know the application the best are the people who use it on a regular basis. They have adapted to it, developed their own processes, and repeated them so often that they've become second nature. The support staff and testers (the people typically writing the bug reports) are a close second to the end users in application knowledge, while developers are often a distant third. Developers are, unfortunately, not mind readers, nor do we possess a crystal ball, so our ability diagnose and fix bugs will live and die with the quality of the bug reports we receive.

What to Include in Bug Reports

So how, you may wonder, does one write a good bug report? Well, for one, you need to know what content to include, and, for that, I would start with item #4 on the Joel Test. Here's what Joel has to say:

A minimal useful bug database must include the following data for every bug:

  • complete steps to reproduce the bug
  • expected behavior
  • observed (buggy) behavior
  • who it's assigned to
  • whether it has been fixed or not

Let's look at these a bit further...

The first bullet point is by far the most crucial. Good reproduction steps point the reader to the part of the application that isn't functioning properly and (hopefully) guide us right to the problem. Without complete reproduction steps, a bug report is basically useless.

A common problem that I see is omitting a reproduction step or two. This sometimes occurs due to laziness or by mistake, but it can also happen because the person writing the bug report assumed that the developer knew what to do at a certain point in the user's process. Never assume! As I mentioned in the beginning, developers don't know the software as well as you think we do.

The next two bullet points are obviously pretty important, too. We need to know what the application is supposed to be doing (the expected behavior), as well as what it is doing (the bug). The combination of these two items is what I typically call the problem statement.

The fourth bullet point (the assignee) is pretty self-explanatory. The last bullet point is often referred to as the bug's status, and this is usually pretty straightforward. However, I have seen people invent some rather nebulous terms for issue status. I recommend naming the statuses as clearly as possible (i.e. "Open", "In Progress", "Development Complete") and providing detailed definitions for each status within your documentation.

Joel's list is a pretty good jumping-off point, but I think we can take it a bit further. I also recommend including the following pieces of information whenever available:

  1. Who reported the issue? Some problems are isolated to a specific user, and we need to know what makes them different. What type of user are they? Do they have any specific permissions granted (or missing)? Are they on our network, or are they accessing the software externally? This information can be vital when trying to reproduce and/or diagnose issues. This seems like a lot of information to include in a bug report, and indeed it is, but getting (at a minimum) the user's name, contact info, and login ID is at least a starting point in case more information is needed later.
  2. When did the user first notice the problem? Knowing the date and time that an issue first manifested itself can be of vital importance. It often helps us determine if it was caused by something we did (a software change, hardware change, data modification, etc.) at a certain time.
  3. What is the frequency of occurrence? Does this issue happen every time the user performs a specific action, or does it occur intermittently? Does it only occur at certain points of the day? Are all users experiencing this issue, or are only certain users experiencing it (in which case the information in item #1 can be crucial)?
  4. Which environment was this issue observed in? A bug might be found in production, but it could also first be noticed in a different environment (such as QA). This environment could have a slightly different version of the application. It's important to indicate where the bug is observed so that the developer knows a) where they can reproduce the issue, and b) which version of the source code to look at.
  5. Which web browser was the issue observed in? Much of our software these days is web-based, and, unfortunately, applications that function fine in one web browser can be buggy in others. For web applications, always include the browser name and version number in the bug report.
  6. Is there a workaround? What are the workaround steps? This sort of information can help keep users productive while the issue is being resolved. Occasionally, it can also help developers diagnose and fix the bug being addressed.
  7. What is the severity of the issue? Indicating the severity of an issue is important in helping developers prioritize the issues that need to be addressed (please note that an issue's severity is related to, although not necessarily the same as, its priority). It's highly recommended that some sort of severity scale is developed and strictly adhered to. I recommend something like the following:
    • High = Critical functionality is impacted and no workaround exists.
    • Medium = Critical functionality is impacted, but a workaround exists.
    • Low = Non-critical functionality is impacted.

Obviously, not all of the information above is always necessary (severity and workarounds aren't as important for non-production issues) or even applicable (non-web-based applications don't require a browser). However, the point is that a bug can have a lot of variables, and it's important to know as much about those variables as we can so we can diagnose the issue quickly and efficiently.

Including Quality Content

In addition to knowing what content to provide, you'll want to make sure that content is as clear and as useful as it can be. Here are just a few of the things you can do to improve the content of your bug reports:

  1. Use complete sentences with correct spelling, punctuation, and grammar. This seems like a no-brainer, but you would be amazed at some of the positively dreadful bug reports I've read. Don't assume the person reading your bug report will understand sentence fragments or shorthand. Before submitting the report, reread everything you've written to ensure clarity.
  2. Call things what they are called on the user interface. Users will often use industry jargon or come up with their own terminology for certain screens, UI elements or pieces of data. Developers won't know this terminology; they'll be relying on how things are labeled on the screen. Stay away from cryptic terms whenever possible.
  3. Use ordered (i.e. numbered) lists. This is a rather simple thing to do, but it can help aid in clarity of communication between team members (e.g. "can you elaborate on reproduction step #4?").
  4. Take screenshots. This one is pretty self-explanatory. We've all heard the old saying that a picture is worth a thousand words. While the phrase "refer to screenshot" might not save you from typing a thousand words, it will probably make your life easier.
  5. Use screenshots to include examples of form input data. Here's a common scenario: a user fills out a lengthy form, clicks a submit button, and then receives some nasty error. As much as it might suck, any one of those pieces of data could have caused the issue, and you'll need to include them all. But instead of typing all of those form values into a note in your bug report, you can create a screenshot while you're reproducing the bug. Fill out the form, then take a screenshot before you click the submit button.
  6. Save your reproduction steps! You just typed a TON of words on how to reproduce a problem... do you want to have to retype all that every time this screen breaks? Of course not! Save reproduction steps for common tasks into text files or Word documents, and store them in a folder on your hard drive. Include the name of the UI at the beginning of the file name so you can locate them quickly.
  7. Consider developing (or improving) your own template for bug reports. If your bug reports are hand-written, consider developing a Word template. If you're using a commercial tool for bug tracking, look into customizing it. If you find that the developers are constantly coming back to you asking you for a specific piece of information, that's a strong indication that it should be included in all bug reports.

The Developer's Responsibility

Okay, okay... I've spent a lot of time berating support staff and testers over their bug reports. But, as it turns out, developers aren't perfect either. There are a few things we should always be doing with bugs that get assigned to us:

  1. If you can't find the problem, at least add notes for other developers. Investigating bugs can often feel like "doing science"... no matter how methodical you are, you won't make a discovery until you make a discovery. Diagnosing bugs can be time consuming, and it can be frustrating and costly to retread the same ground that others have already covered. Add as much detail as you can to the bug report about where you looked and what you tried. Try to be as specific as possible; include names of source code files, subroutines, or even line numbers. It sounds like a lot of extra effort, but it may save you or your teammates time later on.
  2. After fixing a bug, add instructions related to how to test changes. Usually the reproduction steps are the testing instructions. But sometimes a change can have a far-reaching impact and require re-testing a variety of screens or functionality that (seemingly) had nothing to do with the original bug. In these instances, add a note to the bug report calling out what areas should be tested.

Conclusion

Bugs suck, but bug reports don't have to suck. By following a few guidelines, we can make bug reports clearer and more informative, which makes them more useful to developers.

My Big-Ass List of Software

Last Updated: 7-June-2015

Introduction

The purpose of this entry is simply to compile a list of the Windows software I use the most. Except for the section that cover Chrome extensions, everything listed here is Windows desktop software compatible with Windows 7 and higher (no Windows Store apps, no Mac stuff, etc.). I provide the name of each application along with a brief description and a link to where you might find it. I also point out whether or not it is available via Ninite, an excellent web site that allows you to download and install many applications at once. Obviously lists like this are continuously evolving, and, hence, I will make every effort to keep this list up-to-date.

I would be remiss if I didn't mention Scott Hanselman's Ultimate Developer and Power Users Tool List for Windows. It's an incredibly useful list and I highly recommend you add it to your bookmarks. You'll find that much of the software I list below also makes an appearance on his list (and, indeed, many appear here because of his excellent list).

Windows Applications

Utilities

CCleaner: Without regular maintenance, all PC's accumulate excess cookies, temp files, and all sorts of other unwanted crap. For keeping a system clean, I use CCleaner Free. For more info on how to use it, check out this article from the How-To Geek, especially if you're considering using some of CCleaner's extended features.
Where to get it: Official Site

Revo Uninstaller: Removing an application via the Windows Programs and Features menu will run that application's uninstaller, which can sometimes leave behind unwanted files, folders, and registry entries. Removing an application with Revo Uninstaller allow you to get rid of this extra junk.
Where to get it: Official Download Page or Ninite

Everything: If you need to locate files or folders on your hard drive by name ultra-fast, skip the built-in Windows search and go for Everything.
Where to get it: Official Site or Ninite

TeraCopy: Provides a faster copy-and-paste for Windows, along with a handful of advanced options.
Where to get it: Official Site or Ninite

7-Zip: A solid utility for compressing folders to (or extracting them from) archive files. It can extract most major formats, and will compress to .zip files or it's own .7z archive format.
Where to get it: Official Site or Ninite

WinDirStat: This app will analyze your drives and give you a visual representation of how much space your files and folders are using. This is super-handy when you're trying to free up hard drive space.
Where to get it: List of Download Locations or Ninite

TreeSize Free: Another tool for analyzing which folders are taking up the most space on your hard drive. I like WinDirStat's nice visual representation slightly more, but this one works great, too.
Where to get it: Official Site

Speccy: This is a handy app for when you're not too sure what a system's specifications are and you don't feel like digging through the Windows Device Manager (or taking the damn thing apart).
Where to get it: Official Site

Virtual CloneDrive: This is a solid free choice if you find yourself needing to mount image files (such as ISOs). It sits in your system tray and is there when you need it.
Where to get it: Official Site

Classic Shell: If you're like me, you weren't too happy with Microsoft's decision to remove the classic Start menu from Windows 8. Luckily, there is a solution: just install Classic Shell!
Where to get it: Official Site or Ninite

Partition Wizard Free Edition: If you run into situations where you're resizing file partitions on your hard drive(s), the free version of this tool offers a bit more flexibility than the built-in Windows Disk Management interface (such as the ability to utilize free space located before a partition when extending it).
Where to get it: Official Site

Magical Jellybean Keyfinder: Whether your system is royally screwed up from malware or you're just craving a fresh start, nothing beats a total reinstall of Windows. Before you start this process, you'll want to make sure you have your Windows Product Key on hand. If you're not sure what it is, Magical Jellybean Keyfinder can extract this information from your current Windows installation.
Where to get it: Official Site. Note: When running the install, make sure you choose the Custom Install option and uncheck the box to avoid installing unwanted software.

Security

A Note on Anti-virus Software: Choosing anti-virus software is not as straightforward as one would like. Products that were good a few years ago might suck now (and vice versa), either because they're not offering up-to-date protection against the latest viruses, are too resource-intensive, have crummy interfaces, or flat-out don't work. Because of this, the so-called "best" anti-virus software is hard to identify and constantly changing. Of course, plenty of knowledgeable people on the web have their take on the matter. The Lifehacker team seems to really like Avast. If you want to do a bit more homework, sites like AV Comparatives and AV-Test offer in-depth analysis of how anti-virus applications compare to one another. The challenge is to find something that is lightweight but still offers solid protection. Personally, I've been using Windows Defender (which is built-in to Windows 8 and above) and really haven't had any problems, but I'm a knowledgeable user with relatively safe browsing habits. (NOTE: Windows 7 and earlier does not offer built-in anti-virus protection, but you can download Microsoft Security Essentials for free.)

I won't go as far as telling you what anti-virus product to use, but I will offer a few general words of advice:

  1. Choose a free product. With the number of free options available, there really isn't any reason to pay for anti-virus software.
  2. Choose a product that offers real-time protection in addition to on-demand scans.
  3. Keep your anti-virus software up-to-date. Your application is really only as protective as it's most recent virus definitions update. Chances are you can configure it to automatically update during off-hours, so make sure to set that up.

Malwarebytes: Scanning with Malwarebytes will detect and remove things that your antivirus software won't look for (spyware, trojans, etc.). There is also a premium (i.e. not free) version that adds real-time protection.
Where to get it: Official Site or Ninite

Productivity

Evernote: This is just one of the many cloud-based note-taking apps out in the wild. I like Evernote because it offers a consistent experience across it's many user interfaces (browser, desktop app, and mobile app).
Where to get it: Official Site or Ninite

MarkdownPad: A solid markdown editor. I use this app for writing all of my blog entries (including this list).
Where to get it: Official Site

f.lux: f.lux will adjust the color temperature of your display at night, which helps reduce eye strain (and may improve our sleep patterns).
Where to get it: Official Site

Web Browsers

A Note on Web Browsers: Web browsers are sort of like anti-virus software or text editors: eventually, everyone picks a favorite. To a novice or casual PC user, the web browser is the Internet, so it's important to choose a good one. If you're a web developer (like me), you'll probably have to spend a little bit of time in several different browsers, but you will still spend 95% of your time using one in particular. Luckily for all of us, web browsers are free, so there's nothing keeping you from trying out a whole bunch of them. I won't discuss each one, but the major browsers are Mozilla Firefox, Opera, Microsoft Internet Explorer (soon to be replaced by Microsoft Edge), Apple Safari, and my personal favorite - Google Chrome.

Google Chrome: Of all the browsers I've used, Chrome provides the best user experience. Like most modern browsers, it offers a multi-tabbed interface. Most importantly, it is lightning fast (thanks to Google's awesome V8 JavaScript engine). Chrome is highly customizable via the many extensions available (I describe some of my favorites later in this post). It is also auto-updating, so as not to bother users when a new version is available. This is sort of a blessing and a curse: 95% of the time it's great, but occasionally a feature you love or rely on will change or vanish completely with no warning. The most recent example of this is their dreadful redesign of Chrome's bookmark manager (which you can undo via the steps in this article).
Where to get it: Official Site

Media (Players, Encoders, Rippers and Burners)

VLC: The only audio/video player you'll ever need. Just download it and never worry about codecs again.
Where to get it: Official Site or Ninite

Handbrake: A video encoder app with a variety of uses. I mostly use it for ripping DVDs.
Where to get it: Official Site

DVD Flick: This app allows you to create a new DVD out of one or more disparate video files on your hard drive.
Where to get it: Official Site

ImgBurn: An invaluable tool for burning DVDs, ripping DVDs to ISOs, etc. Where to get it: Official Site or Ninite

CDBurnerXP: I don't burn too many audio CDs these days, but, when the need arises, this is my go-to app.
Where to get it: Official Site or Ninite

File Readers

Adobe Reader: Adobe's free PDF viewer (duh).
Where to get it: Official Site or Ninite

Adobe Digital Editions: If you're a fan of eBooks, then you're probably familiar with the EPUB format. There are a lot of EPUB readers out there, but I like the minimal design of Digital Editions (plus it's free!).
Where to get it: Official Site

Comic Rack: That's right: I'm a comic book nerd. Comic Rack is my go-to app for thumbing through comic book files (CBR or CBZ) within Windows.
Where to get it: Official Site

Developer Tools

Microsoft Visual Studio: Visual Studio is the IDE for doing .NET development, but it can be used for non-.NET development as well. It comes in a variety of flavors; check out the official site for more details.
Where to get it: Official Site

LINQPad: When you just want to write some .NET code and don't need all the bells and whistles that Visual Studio offers, LINQPad is a handy tool. It allows you to write simple programs in C#, VB, or F#. It also allows you to query SQL Server databases via SQL, LINQ to SQL, or LINQ to Entities.
Where to get it: Official Site

Microsoft PowerShellISE: A simple scripting environment for PowerShell with a command prompt in one pane and a script editor in the other.
Where to get it: It's built-in to Windows. Once you enable PowerShell, the ISE should also be available.

Microsoft SQL Server Management Studio: A full-featured environment for working with SQL Server databases.
Where to get it: It's an available option when you install SQL Server.

Query Express: From the same developers that created LINQPad comes this simple, free query analyzer for SQL Server databases.
Where to get it: Official Site

Notepad++: A simple text editor can be a developer's most vital tool. Notepad++ takes the simplicity of Notepad and adds syntax highlighting, themes, macro support, and loads more.
Where to get it: Official Site or Ninite

Atom: I just started using Atom, but I'm already starting to think it could edge out Notepad++ as my favorite stand-alone text editor. It's a tad slower when first starting, but I like the look-and-feel a lot more, and it has a really nice interface for installing and uninstalling extensions (which they call "packages") and themes.
Where to get it: Official Site

WinMerge: Every developer needs a tool for comparing and merging text files. Truthfully, my favorite diff tool is the one inside Visual Studio, but, when I'm looking for something standalone, I go with WinMerge. It has a few extra bells and whistles, such as the ability to compare folder contents.
Where to get it: Official Site or Ninite

Telerik Fiddler: Fiddler is described as a "web debugging proxy". It lets you analyze and "debug" HTTP traffic in real time. It also has a Composer tab that lets you build and send HTTP requests. As someone who develops web services and applications that consume web services, I assure you that this functionality comes in handy on an almost daily basis. This is a vital tool for web developers, and, seeing as how it's free, there's no reason not to grab a copy.
Where to get it: Official Site

Telerik JustDecompile: There are a number of tools on the market for decompiling .NET assemblies. I've stuck with this one because it's fast, easy to use, and, best of all, free.
Where to get it: Official Site

NimbleText: Here's a scenario: I have to write a line or two of code for each item in a list. Does this sound familiar? Doing this sort of copy-paste-edit over and over until your fingers are sore can be a real pain in the neck. That's where NimbleText comes in. Paste your list into the top panel, type your template into the middle panel, and voila - out comes your code! This is such a simple concept, but I've run into uses for it more times than I can count.
Where to get it: Official Site

NimbleSet: If you thought the last one was stupid-simple, wait until you see this one! Have you ever had two lists that you needed to merge (get the union) or find common entries (get the intersection)? In the past, I've always had to do this in Excel, and hated trying to remember where to find all its filtering options (don't even get me started on that damn ribbon!). But with NimbleSet this easily becomes a 30-second-or-under task: You just copy-and-paste your lists into the two panes provided, click a button, and you're done!
Where to get it: Official Site

Chrome Extensions

General

Reddit Enhancement Suite: I spend a LOT of time on Reddit, and RES adds a load of features that make my Reddit browsing much more productive (or unproductive, depending on your perspective). I think it's worth it for the dark theme alone.
Where to get it: Chrome Web Store

Google Mail Checker: It tells you how many unread messages are waiting in your Gmail inbox. Couldn't be simpler. Where to get it: Chrome Web Store

Privacy and Security

AdBlock: This is probably Chrome's most ubiquitous ad-blocking extension. It has a few advanced options, such as allowing you to whitelist specific domains or pages.
Where to get it: Chrome Web Store

Ghostery: Protects your online privacy by blocking tracking cookies and related junk.
Where to get it: Chrome Web Store

Shield for Chrome: Monitors your other Chrome extensions to determine if any of them are doing malicious things.
Where to get it: Chrome Web Store

Media

Google Cast: Google Chromecast is one of the cheapest and easiest ways to watch stream content like Netflix or HBO Go on a computer or mobile device and display it on a television. All you need is the Chromecast, a TV with an HDMI jack, and this extension.
Where to get it: Chrome Web Store

Videostream for Google Chromecast: Allows you to stream downloaded video files (as opposed to streaming content) to your TV via your Chromecast. Where to get it: Chrome Web Store

Developer Tools

Postman REST Client: Postman is a simple tool for constructing and sending HTTP requests, which comes in handy when you're working with RESTful web services. If this sounds a lot like the Composer tab in Fiddler, that's because it is. I like both tools: Fiddler is a bit more flexible, but Postman has a slightly cleaner interface. I can't pick a winner... you decide!
Where to get it: Chrome Web Store

DevTools Theme: Zero Dark Matrix: I absolutely love Chrome's DevTools, but I prefer to use a dark theme. Chrome doesn't come with a dark theme out-of-the-box, but this extension will give you one. Please note: you will have to do some extra configuration for Chrome to apply this theme. See this article for more details.
Where to get it: Chrome Web Store

Telerik Kendo UI Chrome Inspector: I use Telerik's Kendo UI suite of HTML5 widgets all the time. This extension will add a "Kendo UI" tab to Chrome's DevTools, which will give you some great details on the widgets being used on the current page.
Where to get it: Chrome Web Store

Dimensions: This is another simple-but-powerful tool. Turn it on and you've instantly got a ruler for measuring the pixels between elements on the current page.
Where to get it: Chrome Web Store

Fontface Ninja: This extension offers a quick and easy way to determine a specific font's face and size: Just turn it on and hove your mouse over the text, and a tooltip will pop up with the details.
Where to get it: Chrome Web Store

JavaScript: call(), apply(), & bind()

Introduction

JavaScript functions are actually objects themselves, and, like any other objects, contain properties and methods. Three of these methods, call(), apply(), and bind(), can be used to provide a calling context for a specific function, thereby treating ordinary functions like methods. This post aims to briefly describe and demonstrate how to use these methods (albeit with a contrived example).

Initial Setup

Our initial setup code is pretty straightforward: we have an object called person that has two properties (firstName and lastName) and one method (getName()). Running the code will log the person's full name to the console.

var person = {  
    firstName: "John",
    lastName: "Doe",
    getName: function() { 
        return this.firstName + " " + this.lastName; 
    }
};
console.log(person.getName()); //John Doe

The call() Method

At some point later in our application, we define a function to set the firstName and lastName properties at the same time.

var setName = function(newFirst, newLast) { 
    this.firstName = newFirst; 
    this.lastName = newLast;
};

The problem here is that we've declared this function outside of our person object. In this context, this refers to the global object (i.e. the Window object if our code is running in a web browser). So neither invoking the method directly on person (i.e. person.setName("Joe", "Schmoe")) or invoking it without indicating an object (i.e. setName("Joe", "Schmoe")) will do what we want it to do. How can we invoke this function as if it were a method on the person object? Our answer lies in the call() method.

The call() method allows you to invoke a function in the context of a specific object, which you provide as the first argument. In other words, the call() method lets you treat any function like a method on an object of your choosing. Any additional arguments provided are passed to the function being called (so invoking a function with n arguments via call() requires n+1 arguments).

setName.call(person, "Joe", "Schmoe");
console.log(person.getName());  //Joe Schmoe

In the above example, the setName() function is being called as if it were a method on the person object. So the code works the same way as if we had just given person a setName() method in the first place and were now invoking it like person.setName("Joe", "Schmoe").

The function being called doesn't have to be declare outside of an object; it can even be a method declared inside a different object. The example below utilizes the setFullName() method defined in customer to perform the same operation on person.

var customer = {
    ...
    setFullName: function(newFirst, newLast) {
        this.firstName = newFirst; 
        this.lastName = newLast;
    }
};
customer.setFullName.call(person, "Joe", "Schmoe");
console.log(person.getName());

The apply() Method

The apply() method functions almost identically to call(). The only real difference is that, while call() accepts a variable number of arguments, apply() only accepts two: the context object (i.e. the value of this inside the function) and an array of arguments to be passed in to the target function. So the equivalent code to our call() example utilizing apply() is written as follows:

setName.apply(person, ["Joe", "Schmoe"]);
console.log(person.getName()); //Joe Schmoe

The apply() method is obviously a bit more robust than call(), and can be used in scenarios where the number of function arguments is not known until runtime. Remembering which one is which can be a little confusing at first; I find it easiest to just remember the mnemonic "A for arrays, C for commas".

The bind() Method

The last method we will discuss is the bind() method. Much like the other methods we've discussed, the first argument supplied to bind() is the context object (i.e. the value of this inside the function). Unlike those other methods, bind() does not invoke a function when called. Instead, it returns a new function. Let's demonstrate this using another example:

var setPersonName = setName.bind(person);
setPersonName("Suzy", "Schmoe"); //Suzy Schmoe
console.log(person.getName()); 

The example above takes setName(), binds it to the person object, and stores it in a new function called setPersonName(). When this new function is invoked, it will modify the person object's properties. Notice that setPersonName() behaves like a method, but is not invoked like one. Bind is useful for creating shortcut functions (as in the above example) or in situations where you want to pass methods as anonymous function arguments to other functions.

Completed Example Code

var person = {  
    firstName: "John",
    lastName: "Doe",
    getName: function() { 
        return this.firstName + " " + this.lastName; 
    }
};
console.log(person.getName()); //John Doe

var setName = function(newFirst, newLast) { 
    this.firstName = newFirst; 
    this.lastName = newLast;
};

setName.call(person, "Joe", "Schmoe");
console.log(person.getName());  //Joe Schmoe

var customer = {
    firstName: "Sam",
    lastName: "Smith",
    setFullName: function(newFirst, newLast) {
        this.firstName = newFirst; 
        this.lastName = newLast;
    }
};

customer.setFullName.call(person, "Joe", "Schmoe");
console.log(person.getName());  //Joe Schmoe

setName.apply(person, ["Joe", "Schmoe"]);
console.log(person.getName()); //Joe Schmoe

var setPersonName = setName.bind(person);
setPersonName("Suzy", "Schmoe"); //Suzy Schmoe
console.log(person.getName());

Type Systems

Overview

Static vs. dynamic? Strong vs. weak? What does it all mean? And what's this I keep hearing about ducks? In this post, I will try to shed some light on these mysterious terms...

Static vs. Dynamic Type-Checking

Static type-checking is the process of verifying a program's type safety before it is run (i.e. at compile time). But what does it mean to "verify a program's type safety"? Well, it simply means to insure that types are being used as they are supposed to (int's are used like int's, string's are used like string's, and so on). Therefore, we would expect a statement like int x = "one"; to fail to compile in a statically type-checked language. C, C++, Java, and C# (*see note below) all behave this way.

Dynamic type-checking, on the other hand, is the process of verifying a program's type safety at runtime. Here are a few JavaScript expressions that would fail to execute due to dynamic type-checking:

var n = 123;
console.log(n.toUpperCase()); //TypeError (n is not a String)
n(); //TypeError (n is not a Function)

It is pretty common for interpreted languages (such as JavaScript, Ruby, and Python) to have dynamic type-checking, but some compiled languages have this trait as well. It's also possible for a language to have both static and dynamic type-checking.

*NOTE: C# 4.0 and above allows a variable to be declared as dynamic. This behaves similarly to declaring a variable as an object, except that expressions involving these variables are not type-checked at compile time. This was introduced for interoperability with dynamically type-checked languages.

Strong vs. Weak Typing

The "strong" vs. "weak" type system comparison is not as cut-and-dry or as well-defined as the static vs. dynamic comparison. The difference between strong and weak type systems has to do with how the language will handle variables which do not meet the expected type for the operation. A "strongly" typed language will typically throw an error, while a "weakly" typed language will attempt to convert the argument(s) to complete the operation.

Consider the expression 3 + "4". Attempting this in Ruby will throw a TypeError, whereas JavaScript will coerce the 3 into a string and produce the result "34". Therefore, it can be said that Ruby is strongly typed and JavaScript is weakly typed (note that both languages use dynamic type-checking).

Duck Typing

So what, then, is duck typing? The answer typically given to this problem is the following:

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.

Yeah, I'm not wild about people who answer straightforward questions with riddles, either.

Consider instead the following JavaScript function and example usage.

var maxLength = function(a, b) {
    return Math.max(a.length, b.length);
};
console.log(maxLength([1, 2, 3], "hello"));

The two arguments could both be strings, could both be arrays, or could be one of each. Or they could be something else altogether. As long as they both have a length property, the function goes quietly about it's business. This is duck typing.

Duck typing is something that can really only manifest in languages with dynamic type-checking, although it is not limited to weakly typed languages. Duck typing differs from languages which use nominal typing, where variables are determined to be type-compatible by comparing specifically declared types. Structural typed languages offer something of a middle-ground between duck typing and nominal typing; two variables are type-compatible if their entire structures are the same (i.e. all of their properties and methods).

Further Reading

If you're looking for more detailed explanations, Wikipedia has a fairly extensive entry on type systems, which also links to entries on the majority of the topics discussed above. I personally find their comparison of type systems found in major languages to be a more useful jumping-off point.

Enforcing one-to-(zero or one) Relationships in a RDBMS

Overview

The following sections outline approaches one might take to enforce a one-to-(zero or one) relationship in a relational database.

Approach 1: Store the data in the same table.

This is pretty self-explanatory. If the data is truly 1:(0..1) there is no logical reason the data can't coexist in one table. Just add the additional columns that would go in the child table to your parent table and make them nullable.

However, you may actually want to separate your data into multiple tables. This could be because you want to conform to a specific model (the tables represent different entities), or because you have certain physical constraints to consider (limited space, the parent table is already as wide as you're willing to make it, etc.). There are certainly other ways to accommodate this scenario...

Approach 2a: Use a foreign key constraint.

When you create your child table (the (0..1) part of the relationship), add a foreign key column that references the primary key of the parent table. By marking the foreign key column NOT NULL and UNIQUE, you ensure that all records in the child table must reference one (and only one) record in the parent table. The resulting SQL will look something like this:

CREATE TABLE Parent (
    ParentID INT IDENTITY(1,1) NOT NULL,
    ...
    CONSTRAINT PK_Parent PRIMARY KEY (ParentID)
)

CREATE TABLE Child (
    ChildID INT IDENTITY(1,1) NOT NULL,
    ParentID INT NOT NULL UNIQUE,
    ...
    CONSTRAINT PK_Child PRIMARY KEY (ChildID),
    CONSTRAINT FK_Parent_Child_ParentID FOREIGN KEY (ParentID) REFERENCES Parent (ParentID)
)

Approach 2b: Use the same primary key.

This is sort of a twist on the previous approach. You can actually eliminate an extra column in the child table by folding the primary key and foreign key into one column. This can be accomplished with the following SQL:

CREATE TABLE Parent (
    ParentID INT IDENTITY(1,1) NOT NULL,
    ...
    CONSTRAINT PK_Parent PRIMARY KEY (ParentID)
)

CREATE TABLE Child (
    ParentID INT NOT NULL,
    ...
    CONSTRAINT PK_Child PRIMARY KEY (ParentID),
    CONSTRAINT FK_Parent_Child_ParentID FOREIGN KEY (ParentID) REFERENCES Parent (ParentID)
)

Approach 3: Use an intersection table.

The previous approaches work well for 1:(0..1) relationships, where the "parent" entity always exists, but the "child" may or may not exist. But sometimes we can have two independent lists of entities that are occasionally related, and you want to limit them so that an entity in table A cannot be related to more than one in table B, and vice-versa. In other words, it is a (0..1):(0..1) relationship.

In this scenario, the best approach is to use an intersection table. This intersection table will have two UNIQUE, NOT NULL columns that reference the primary keys of the two entity tables. The SQL to create this schema should look something like this:

CREATE TABLE TableA (
    ID INT IDENTITY(1,1) NOT NULL,
    ...
    CONSTRAINT PK_TableA PRIMARY KEY (ID)
)

CREATE TABLE TableB (
    ID INT IDENTITY(1,1) NOT NULL,
    ...
    CONSTRAINT PK_TableB PRIMARY KEY (ID)
)

CREATE TABLE Intersection (
    TableAID INT NOT NULL UNIQUE,
    TableBID INT NOT NULL UNIQUE,
    CONSTRAINT FK_Intersection_TableA_TableAID FOREIGN KEY (TableAID) REFERENCES TableA (ID),
    CONSTRAINT FK_Intersection_TableB_TableBID FOREIGN KEY (TableBID) REFERENCES TableB (ID)
)

What about true one-to-one relationships?

Utilizing Approach 1 from above seems to be the only real solution to this (although, in this instance, the "child" columns should be non-nullable). The other approaches won't work here, because there's no way to split the entities into two separate tables and relate them in a true 1:1 fashion. Attempting to do so would create a sort of chicken-and-egg situation where you can't insert data into either table. The easiest course of action is to use a single table and call it a day.

AngularJS: Communicating Between Controllers and Directives with Isolated Scope

Overview

The problem addressed in this post is a rather common one when developing AngularJS applications. This isn't a particularly difficult problem, but it was one that I struggled with when I started working on medium-sized AngularJS applications... mainly because I didn't have a strong understanding of directives and scope at the time.

Scenario

I have a controller which declares a function called doSomething() on $scope.

angular.module("myApp", [])
    .controller("myController", function ($scope) {
        $scope.doSomething = function() { 
            //something 
        };
    });

I have a custom directive being applied within my controller block.

<div ng-controller="myController">
    <div my-directive></div>
</div>

I want to call my doSomething() function when some event (such as an ng-click) transpires inside my directive. How can I define (and then apply) my directive to accomplish this?

Solution

To do this, I create a directive with an isolated scope. Within the scope declaration, I use '=' to bind a scope property to a function that can then be passed in as an attribute.

angular.module("myApp", [])
    .directive("myDirective", function () {
        return {
            scope: {
                clickFn: '='
            },
            template: "<button ng-click='clickFn()'>Click Me</button>",
            ...
        };
    });

When I apply the directive to an HTML element, I provide an expression (in this case, a function call) to the click-fn attribute.

<div ng-controller="myController">
    <div my-directive click-fn="doSomething()"></div>
</div>

You can use this alternate syntax if you want your directive attribute and scope property to have different names:

scope: {
    onSomethingHappens: '=attrFunction'
},
template: "<button ng-click='onSomethingHappens()'>Click Me</button>",
...
<div ng-controller="myController">
    <div my-directive attr-function="doSomething()"></div>
</div>

Alternate Approach: Use a Service

An alternative to the approach outlined above is to move the function you want to execute into a service. AngularJS services are singletons which can be passed into controllers and directives through dependency injection. I'm not wild about this approach, but it will get the job done. I suppose it is possible to run into scenarios where you need to do this, perhaps because you don't want your directive to have an isolated scope. However, you should be defining an isolated scope if you want your directives to be truly reusable.

Cookies vs. Web Storage

Cookies

HTTP cookies are small pieces of data stored in a user's browser by a specific web site. When that web site is reloaded, the cookies are sent back to the server with each request. Cookies contain a name-value pair, an expiry date, and the domain and path of the server they should be sent to.

To access a page's cookies via JavaScript, use document.cookie. For more information on how to do this, refer to this page.

In ASP, cookies can be created with Response.Cookies and retrieved with Request.Cookies.

Web Storage

Web Storage was introduced with the HTML5 standard. Web Storage is a means of persisting client-side-only data on web sites. Unlike cookies, this data is not automatically sent to the server. Web Storage provides far more capacity than cookies: 5 or 10 MB per origin (depending on the browser) versus cookies' 4 KB. Web Storage comes in two flavors: Local Storage and Session Storage.

Local Storage

Like cookies, Local Storage can retain data between sessions. Unlike cookies, this data does not have an expiration date. This data can be accessed using window.localStorage, as illustrated by the example below.

window.localStorage.setItem("username", "jsmith");
var user = window.localStorage.getItem("username");
window.localStorage.removeItem("username");
window.localStorage.clear(); //clear all items

Session Storage

Session Storage works just like Local Storage, with one key difference: all data expires at the end of the current session (i.e. when the window is closed). Session Storage works just like the examples in the previous section... just replace window.localStorage with window.sessionStorage.

Other Options

Here are some lesser-known alternatives to using Cookies or Web Storage.

Web SQL

Web SQL is an API that can be used to store data in a local relational database. Web SQL is largely considered deprecated, as the W3C ceased work on the specification in November 2010. Web SQL is not supported by IE or Firefox. It is supported by Chrome, Opera, Safari, and the native browsers in Android and iOS. Those browsers that do support it use SQLite as the storage engine.

IndexedDB

The Indexed Database API (or IndexedDB) is an API that can be used to store data in a Key-Value database. IndexedDB is currently supported by Chrome, Firefox, and IE10+. Apple has announced support for future versions of Safari.