Utilizing Ruby Keyword Arguments
The Ruby language is known for it’s flexibility. There aren’t many things that Ruby won’t let you do, whether that’s the ability to pass any data structure to any method or the ability to meta-program pretty much everything. If used unwisely, this flexibility can cause headaches for developers. For example, having a class that takes a generic “args” hash can be great if you need to pass in a hash with dynamic values, but can cause issues debugging since this hash can literally contain anything. Ruby 2.0 introduced a new feature that allows ruby developers to continue to take advantage of the language’s flexibility, while making sure the code is readable and maintainable. Implementing keyword arguments create cleaner and more maintainable code by simplifying future refactors, explicitly stating what arguments should be passed in and outputting more meaningful argument errors.
Positional vs keyword arguments
For the purposes of this post, let’s say we have a Bicycle class that initializes with a make, size, weight and color. If we were to create our class using positional arguments, our class might look something like this:
This might be a good first iteration of a class, but there are quite a few problems with this approach. One of the biggest problems is order specific arguments. If later on down the road (no pun intended) you need to set a default parameter and change the order of the arguments, you will need to find every instance of Bicycle being called and reconfigure the order of the parameters. This can be cumbersome and may cause unexpected bugs, such as a property being set incorrectly since the argument order was never changed:
Refactoring Bicycle to use keyword arguments can help solve this problem and make future changes much easier. Our Bicycle class will no longer be order specific and is much more flexible to change later on. If we need to add our default parameter, we no longer need to change every invocation of Bicycle since each argument is explicitly stated:
This makes future refactors much easier, since we no longer have to be worried about how Bicycle is being instantiated, as long as it’s being passed the correct arguments.
Great! So now our class is flexible and refactoring in the future should be much easier. Now, when other developers look at our class, they will know exactly which parameters are being passed. Here’s what it might have looked like if we had continued to use positional arguments:
From looking at this code, there’s no way to tell what the Bicycle class needs and what parameters it’s expecting. For example, “Canyon” could be anything and there’s no real way to tell that it is actually the Bicycle’s make without finding the Bicycle class and reading over it’s arguments. This can cause problems dealing with old code that you may not remember exactly what it’s doing. Here’s how our instantiation looks like now that we’ve refactored our class to use keyword arguments:
Args Hash vs Keyword Arguments
After looking at this example, you may be saying “Why don’t we just refactor Bicycle to accept an “args” hash and instantiate Bicycle with it’s properties? Future developers will be able to know exactly what’s being passed in and argument order doesn’t matter!” This is a better iteration of the class than using positional arguments, but still causes some serious problems that can be a headache to debug. Let’s go ahead and refactor Bicycle to use an “args” hash:
This looks really clean right? Bicycle accepts an object and just instantiates itself based off that hash’s properties. But what happens when someone forgets to add a property, like color, to the hash being passed in:
Color is now instantiated as nil since there is no color property on the args hash. This can be a major pain to track down and debug, since ruby gives no indication that an argument is missing in your instantiation. Here’s how keyword arguments would handle forgetting to pass the color parameter:
An argument error is thrown explicitly stating which argument is missing. A developer would immediately know they are missing an argument and know exactly which argument needs to be passed in. This, again, causes refactoring to be much easier.
Utilizing keyword arguments in ruby makes development much easier for you and for other developers looking at your code later. They simplify future refactors by eliminating the need for order dependent arguments, explicitly state which arguments need to be passed in for easier instantiation, and provide helpful errors when arguments are missing.