Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, February 12, 2010

Authorization And You

I have been noticing a dangerous anti-pattern recently. It comes in the form of not enough authorization checking. When you have a function in your website that should only be available for particular users (administrators, moderators, whatever), you might be tempted to implement the code to restrict access once, in the view. Consider the following view to delete from a list of users (I snuck in the %: scriptlet tag which I've discussed before):


<ul>
<% @users.each do |user| %>
<li>
<%: user.name %>
<% if @me.can_delete_users? %>
<a href="/users/delete?id=<%: user.id %>">delete</a>
<% end %>
</li>
<% end %>
</ul>


This list might be accessible to everyone, but the deletion should be allowed only to privileged users. This could be a good argument to put all administrative features like this in their own actions/controllers, but there's really no need. Just be sure to check authorization again on the controller side:


class UsersController < ApplicationController
before_filter :construct_me # Set up @me from session

def delete
raise "Nice try!" unless @me.can_delete_users?
User.delete params["id"].to_i
redirect_to "/users/list"
end

def list
@users = User.find :all
end
end


Did you see the extra check that the user is allowed to delete users from within the delete action? That is extra critical. It's easy to consider relying on security through obscurity. Who will try that URL to delete the user if they have no idea what the URL is and what parameters are needed? If the URL were less obvious, you may be even more strongly considering just hiding the URL. While the thought to reduce code clutter and duplicated work may be tempting, it leaves a gaping hole to anyone malicious who decides to start playing around with URLs, searching for administrative functions they shouldn't have access to. You may even get disgruntled former administrators/moderators/whatever who knew the URLs to decide to have some nasty fun with those functions they've been since blocked from.

Security is a hard thing to get right, but there's no excuse to succumb to laziness and knowingly leave dangerous holes in your system. The more powerful the function, the more on edge you need to be for possible ways to break your security.

Note that my snippets include an XSRF hole, but that's a problem for another post.

Friday, January 15, 2010

Design for Extension

I'm in the beginning of writing a simple library, primarily written in Java, with the intention of open sourcing it when it is in a reasonably functional state. As I began work on this project, I decided to try out a new way of designing my classes.

Ruby is my favorite programming language, and one of my favorite aspects of the language is that anything goes. Any object is extensible, even its private methods. Not even the built in classes are safe from extension. This is what's called giving you enough rope to hang yourself. Sure, you could hang yourself with this much power... but you could also use that rope to do some pretty cool things.

Nothing irks me more than non-extensible code. Many times I have run across Java code in the wild that either made a method final that I felt the need to override, or didn't expose a critical bit of API that prevented me from extending it in a key way I needed. It is fine if it is code I can change... I can just make something more open and extend as needed. The problem lies in third party libraries that I don't want to maintain private patches for. This, combined with my love of Ruby's openness, has led me to the goal of making all my Java classes as extensible as possible. The final keyword will only be used in dire circumstances (aka likely never), or to fake a closure in an anonymous class. The private keyword will be reserved only for fields and methods of no consequence.

Before you prepare to write a nasty comment about how ignorant and stupid this design will be, let me jump the gun and tell you why I think it is a bad idea. Either the API becomes locked into potentially poor choices, or the API changes underneath the feet of users of my code. The former is a serious problem if I want to have the freedom to evolve my code, so I opt for the latter. I see exposing a bunch of protected methods as a way to let the users of my code extend my classes in ways I didn't anticipate, yet also imply that it is fair game to change as I see fit. My goal would be to keep public methods as stable as possible, but even those I would be willing to shift around in the name of a better design (be it for code clarity, performance, or whatever).

Granted, this exposes implementation details that aren't really necessary for the client code. However, if someone abuses the details enough to cause themselves pain... I feel the pain is necessary to teach them a lesson. After all, we grow by making mistakes.

The benefit is code that can be essentially patched without needing to modify the source directly, and the ability to use the code in whatever way the client author can imagine. I'm always in favor of more freedom. If it were really that bad of an idea, I don't think Ruby (and other dynamic languages) would be as successful and popular as they are.

As I begin to try out this design mentality, I have run across some important discoveries immediately. It is very important to not depend on fields, because if you do, you limit the ways your code can be extended. Consider:


class Person {
private String firstName;
private String lastName;

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

@Override
public String toString() {
return firstName + " " + lastName;
}
}


The above code is fairly extensible, but what if I wanted to change how getFirstName() works? Maybe I want to prepend a prefix, for example. Regardless, I can override getFirstName() and getLastName(), but toString() will not follow suit to the newly defined behavior in the subclass. Instead, I should have written Person as follows:


class Person {
private String firstName;
private String lastName;

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

@Override
public String toString() {
return getFirstName() + " " + getLastName();
}
}


I could have also resolved this by making the fields protected, or exposing setters. Exposing fields beyond private still doesn't typically sit well with me in Java land (perhaps that's foolishly old school, but I'm stuck in some of my ways). Exposing setters seems to just expose complexity that isn't needed. I may not want my Person to have changeable names. Besides, the ability to redefine a getter by appending, prepending, replacing, or mangling the result is quite different from needing to set the value ahead of time.

The other key aspect I have discovered is to be very cautious when designing your constructors. Constructors in Java pose one of the biggest ways to accidentally lock your code into specific details. For example:


public class Person {
public Person(String username) {
// Connect to a database and load the person
...
}
}


Do you see the problem? Yeah... you have made it so that you cannot construct a Person without connecting to a database and loading a person. Even if you subclass this, you are still stuck with that behavior no matter what. This has a couple possible solutions. You could extract the database connection details like so:


public class Person {
public Person(String username) {
loadFromDatabase(username);
}

protected void loadFromDatabase(String username) {
// Connect to a database and load the person
...
}
}


This will allow a subclass to override loadFromDatabase(String) so that it does nothing. This feels a bit hacky to me, but it works perfectly. The other way around this is to expose an alternative constructor (such as one without parameters). This other constructor could have an empty body, and you could even make it protected if you only want to expose it to give more power to subclasses.

So, I will see how this design works for me, but I already like it. Also, don't take my meaning to say that all methods will be exposed as protected or public. For example, a method that has a very well defined behavior might grow rather large and require some breaking apart. There is no need to make all the pieces protected if they really only make sense as a means of implementing the bigger method. There might be no serious harm in exposing them, but I don't believe in absolute rules either.

There is no One True Way to design. The flaws in this plan might prove more serious than I anticipate, but it doesn't negate that there is some value in allowing free extension. Design is also a bit of a personal adventure, so if this doesn't float your boat, look for alternatives that give you the Happy Feeling.

Any thoughts? Am I destined to fail? Is this something you've tried and enjoy?

Wednesday, January 13, 2010

Static State

Beware of static state. Need I say more?

Ok, I guess I shall, regardless of if I need to. If your automated tests all run from the same context (in my case, a JVM instance), static state will bite you... eventually. You may think you are dealing with the state just fine, but it will hurt you eventually.

I have seen many problems crop up with static state so far. Cached data from the database causes data from one test to bleed into another test. Between tests, you will likely have different data. If the data is not based on a fixed set, it is inevitable that some of the data will be slightly tweaked between tests. If that data is cached, the later test will end up with a cached copy of the earlier test's data. This may not crop up right away, and can happen at any time with cached data. A new test that runs before some old tests could cause the old tests to fail. If the order of tests is not predictable in your automated build, you could get a new ordering that sets up a perfect storm to cause some invalid cached data to stick around and haunt another test.

Similarly, you might have some mock versions of static data that makes testing easier. If you don't clean up the mock data, another test may be expecting the default behavior, and again you are failing because of an indirect cause.

Ultimately, static data can be useful and convenient at times, just be aware that your test environment gets weakened with every static cache or storage you use. You can't always simply try to clean up the cached data when you use it. Consider a class, A, that caches some form of data. Your current test depends on class B, which luckily doesn't use the cached data in A, but it does use class C. You don't deal with cleaning up A. Then, down the road, someone changes C to update or view the static state in A. All of a sudden the tests for B are dependent on static state you had no idea about. Or you are modifying that data unknowingly, and affecting all tests that run after yours that depend on the state of A being in a default state.

I've found the most effective approach is a setup or tear down method in your tests that explicitly clears all known cache. This will ensure no test can hide data that leaks into another test, causing an unexpected (and difficult to track) test failure.

Just be on the lookout for the telltale sign of static state causing failures. If a test class fails on the build machine (or in a group), but it doesn't when run individually... you might be seeing static state showing its ugly head.

Monday, January 11, 2010

Meaningful Comments

Comments are an interesting beast. You can comment your code too much, which will clutter the code so much as to decrease readability. You can comment your code too little such that it is difficult to understand the more complicated areas. You can even not comment at all, and hope the code speaks for itself.

Probably due mostly to laziness, I don't comment my code heavily. When I do, I like my comments to have meaning. I try to write JavaDocs or RDocs for every method, even if it is just a simple comment describing the purpose of the function, with expected behavior. More often than not, I inspect unknown code by looking at the actual implementation. However, sometimes I prefer to jump to the online documentation, so I try to do my part in making sure it is fleshed out.

The problem I see with JavaDocs and RDocs is that it takes diligence to keep them up to date. Sometimes you can unintentionally change the behavior of some method by twiddling with a private or protected method, causing an undocumented change that breaks the usefulness of your JavaDocs and RDocs. Even so, there is benefit in being able to quickly see what a method does, and use that as your base assumptions. If tests prove otherwise, the code can hopefully speak for itself and resolve your conflicts.

The trickiest comments, though, are inline comments. When it comes time to document the details of your code, I've found it very difficult to do a good job of thoroughly commenting it. The problem lies in the fact that the comments are useless until it is time to revisit old code. Once you have lost the context of why you wrote some code, it is very difficult to get it back. We have all run into this problem... you find a bug in some month old code, and start to retrace what the code is doing. You are browsing around, and you see some oddities, but can't for the life of you figure out why the code was written in this way. If you wrote it, you might remember you made some critical decision based on some immediate goal, but the goal and decision are now completely lost.

Therein lies the problem. Code needs to be documented to show why you wrote it that way, not what that code does. This comment is useless:


// Add 1 to the count of items.
itemCount++;


If you describe why you did something, you might give your future self a break when it comes time to track down an error, so try a comment more like:


// The item count is off by 1 because the first item is
// implicitly dealt with already.
itemCount++;


Now, this still leaves the problem open of when to write those comments. The best advice I can give is to look for those moments that you had to think a while to figure out what to do, or the code just looks too complicated. The best solution is so obvious it documents itself, but that can sometimes be rather difficult to achieve.

What are your guidelines of when to document code? Do you still run into those "what was I thinking" moments?

Friday, January 8, 2010

Peer Demo

A lot of software practices make sense when described. Source control, automated tests, automated build server, etc. Even the most obvious practices become crystal clear the moment they have a real impact on your development. That automated test that caught the bug as soon as you created it. The automated build that notified you of an old test that is now failing because of a new bug. A massive refactoring that turns out to be fruitless, easily reverted with some easy source control commands. An old diff helping you regain context of why you (or someone else) made a particular change.

Recently I had the revelation with simple peer review. Not even peer review of code, but the simple practice of demoing your finished code to a peer. Before going in to this recent demo, I fully understood the benefits of such practice, but it transformed a neat idea to a must do.

Now, like most developers, I am very obsessive about my code. I do everything I can to make sure it is polished and perfect when it is time to deploy. I try to write as many reasonable unit tests as I can. I constantly exercise my code, both with test driven development and with actually looking at the visible output to make sure it is doing what I expect. With all my obsessing over my code, I tend to finish with a fairly confident feeling that it is ready for production. Don't misunderstand my meaning to think that I feel my code is perfect, or even necessarily good, and most definitely not bug free, but I take pride in my craft and try to call it done when I really think it is done.

There is a big problem though... like every other developer, I am human. I don't anticipate a certain kind of error condition. I forget to check a particular path in the code. I over complicate the solution and miss a way to make the UI a lot simpler and easier to use. Ultimately, I am left with a couple bugs that I just couldn't quite run across.

For one, several, or all of the above reasons, I end up with a demo that makes blatantly clear a few key mistakes that I made. This happened with my most recent demo. Together, the reviewer and I filed quite a few bugs in our issue tracking software that I needed to resolve. Not all were directly caused by me and my code... some were issues that dated back quite a while... but quite a few of them were most definitely because I hadn't exercised the code quite as thoroughly as I had thought.

The key thing I take away from this reminds me of Jeff Atwood's post on not going dark. I'm not afraid to share my code as I develop it. In fact, I enjoy showing off a small snippet or clever bug fix I just wrote that I feel does something neat. I similarly like to see when other developers finish something they feel proud of. However, I still end up writing my feature in relative darkness. The demo is like shining a flashlight in the corners that I didn't get to. By having another person walk through your code, or even just the simple act of showing that it works, you will often end up seeing a different perspective that you never thought of while you were working. Sometimes you run across code that had been manually tested, but changed since the tests and is now broken. Whatever the case, you will inevitably run across something that could be improved upon that you didn't quite catch.

It doesn't even have to be a bug, necessarily. For example, in the demo, we decided that the action we were exposing to the user could benefit from being run multiple times, sometimes. So, we made an easy to access link that allows you to retry the action when you want to, which saved the user from the need to search a table for the same row to run the action again. This was a missing feature in the original spec, not exactly a bug. Nevertheless, the demo made this change an obvious need. Perhaps it is the halfway point between just deploying new code, and dogfooding your code. In the absence of being able to dogfood your code, a simple demo of all new features will expose a good chunk of what you would have been able to find through dogfooding.

So before you deploy that new feature... grab a friend and just demo it to them. Even if you don't find a single issue, at least you will be more confident that your code is ready.

Monday, January 4, 2010

Love Hate

Is there a language feature you absolutely adore? For me it's closures. Blocks in Ruby make me warm and fuzzy, and anonymous functions in JavaScript make me giddy. Anonymous classes in Java make me... puke. Sorry, Java just doesn't have good closure support.

If you have a language feature you adore, chances are good that there is a language feature you loath. For me, it is the ternary operator. I don't care which language you are talking about, ternary operators cause me to run in the corner and hide, cowering, and waiting till they go away, on their merry business.

Perhaps it is a bit of an irrational loathing. I like dense code, but I want my dense code to be readable. I find nothing wrong with something like:


str = list.map { |x|
x * x if x
}.compact.uniq.sort.join ","


But write something like:


str = value.nil? ? "null" : "'#{value}'"


And I will refactor your code. Whatever the case, a ternary operator makes me stop and think more carefully about what is going on whenever I see it. Code nirvana, to me, means code that is intuitive and self documenting. Method names like compact, uniq and sort all lend themselves to self documentation. The ternary operator, on the other hand, feels cluttered and doesn't lend itself to immediately understanding what the purpose of the code is.

I will go to great lengths to avoid a ternary operator. I prefer the more verbose if control structure. Ruby makes the deal even sweeter since an if is an expression (like everything else in the language). I will happily pay the cost of the added lines of code, though, if it means I can stay clear of any ternary code.

If you feel you must use a ternary, do me a favor and use just one per expression. Not just use one, do nothing else on that line of code, so the ternary avoids external clutter to make it even more non-obvious what is going on in the code.

Are there language features that make you cringe every time a fellow developer uses it, regardless of context?

Wednesday, December 30, 2009

Blame Yourself First

Why is it that the stupidest, most obvious bugs are the ones you end up spending half an hour on? Did I say half an hour? Make that several hours... maybe even a day or more, sometimes. Consider the following JavaScript code (written with jQuery):


$(function() {
$(".clickme").click(function() {
var link = $(this);
link.css("color", "gray");

finish = function() {
link.css("color", "blue");
};

$.ajax({
url: "/my/remote/url",
success: function(data) {
// ... process the result ...
finish();
},
error: function(data) {
// ... process the error ...
finish();
}
});

return false;
});
});


I wrote code very similar to this recently, albeit a bit more complicated, but with the same bug. Can you spot the bug? What if I renamed the finish function variable to iAmABonehead? Well, if that doesn't make it obvious, you might want to brush up on JavaScript, if you plan on using it much. Instead of creating a local reference to a closure named finish, I was creating a global reference to a closure named finish that gets overwritten every time the click handler fires. Thus, a quick couple clicks in a row, and you will end up with some permanently gray links.

Here's the funny part, though. I did what every good software engineer does... I saw the behavior in my browser of choice (Chrome at the moment), and thought... gee, that's an odd bug in jQuery with Chrome. My code surely doesn't cause that problem. How can I figure out a way to work around this odd bug?

Thankfully I caught myself, and gave myself a good reprimand:

Self! Don't be such an idiot! You are surely the cause of this bug... drill down a centimeter and you will find it!


So I took this quite excellent advice and decided to give the same bug a shot in Firefox. My reason being that surely our version of jQuery is thoroughly tested with Firefox... if the bug comes up again, it's either jQuery, or me. Except that it probably isn't jQuery.

A quick test indicated that jQuery I was the likely cause of the problem. A couple minutes of a closer inspection of the code and I found the accidental global and fixed my bug.

I guess this is the "Science" aspect of Computer Science. When dealing with bugs, you need to treat it like a (hopefully) repeatable experiment. Form a hypothesis on why you are seeing your experimental results, then conduct further tests and experiments to drill down until you have found and squelched the bug.

For your first hypothesis, don't think about which of your frameworks is likely causing the bug. Eliminate them as the possible issue. The bug is 99.99942% likely to be in your code. When I come across a bug in fresh code, it's weird how the frameworks and platforms I am using are the first my mind blames. It takes all those times being wrong with such accusations before I finally started to stop myself and reconsider which part of my code might exhibit the behavior.

The sooner you blame your own code, the sooner you will find the bug. It helps to take a breather and come back with fresh eyes, too. Usually the bug isn't just in your code, it's something so blatantly obvious that your eyes skip over it and can't see the semicolons for the braces.

Wednesday, December 23, 2009

Better Estimation

Your time estimations suck. I don't care how accurate you are sure they are, they suck. The reason they suck is not because you are a bad developer, or you don't have experience estimating... they suck because you don't know the whole story yet.

It is impossible to predict everything that will come up during the course of your development iterations, and many things will come up that you had no way of predicting. Even if you break down your problem to the tiniest, bite sized pieces, you will have emergencies come up. Your colleague's dog will get sick causing him or her to be out half a day, making it impossible for you to complete the planned integration between your 2 services. A user won't be able to input their Woozit into your Whatzit page because of some overly zealous input validation you shipped last month, and it will take a day to track it down and fix it. You will meticulously estimate each minute detail of how to build the new Bazzle Integration Service, and you will get it all perfectly done, but forget to leave some extra time to do some dry runs at the end, only to realize their system doesn't quite match up with yours the way you expected, and 2 more days will be lost patching up the differences.

I guarantee you, no matter what you do, your estimates cannot be perfect. So stop thinking they can be, and figure out a way to adjust for the unadjustable.

I can't tell you how much I would love to see Joel's Evidence Based Scheduling implemented at my workplace. However, it's always something to tackle next iteration. Beyond the lack of commitment from the whole team, it seems like a lot of work to track the time you spend on everything, even though the results, I am sure, are spectacular.

If you can't commit to such effort, I suggest a more low-tech technique. For every work item that you are a little unsure of, add in a task to figure things out. Break your work items down to the most meaningless, mindless 20 minute tasks you can, and set them as half hour tasks... hour tasks... or even 2 hour tasks. You will have to test that 20 minute's worth of coding, after all. Understanding exactly what you are building will help prevent missing key aspects that might have been forgotten. More things will come up as you are in the details of your implementation, but I find it helps to try to think of as many contingencies as possible.

When you are done with your estimation, however you do it, double the final amount you have. This gives you significant buffer to help you reach your milestone, and it will help address a lot of the unknowns that will crop up between now and the milestone. Then, adjust this 2x multiplier each iteration based on how long it took the last iteration. If your initial estimates for the last iteration was 1 month of work, and you doubled it to 2 months, but you finished in 1.5 months, then multiply the next amount by 1.6, to be safe. Keep track of your multiplier at every milestone, and over time you should be able to develop a multiplier that works for your team to hit almost every milestone.

This is a much cruder form of Evidence Based Scheduling, but consequently, much easier to employ. It may not result in perfect results, but if you are missing every deadline, it should help better than continuing down the same path over and over and over, like a broken record.

Monday, December 21, 2009

Protect Your Environment, Part 2

Last time I talked about separating your environment, and automating it such that almost nothing needs to be customized outside your source control. Today, I want to expand on that thought a bit and specifically talk about your build environment. If you aren't using a build environment like Cruise Control, you really should be. By automating your build, you can quickly detect when you've changed code that causes a regression test to fail, or if you've otherwise unintentionally broken things.

I'm not really trying to espouse the benefits of an automated build system, though, so I'm going to assume you have one set up. The next step is to protect your build environment.

With the build environment, it's especially important to keep everything in source control, and contained within the root directory. If you can't have 2 parallel checkouts of your source simultaneously running your build without failing in some way, you are doing it wrong.

This means a few things. Primarily, do not depend on external files or libraries. If your code looks for a file in /usr/share/myconfig.properties, then move that file to within your root checkout and change your code to point to that properties file with a relative path instead. Commit every jar or other runtime library into source control, and point your build to load the files locally.

What this gains you is flexibility to have parallel development. You can have a branch that represents what is currently deployed, and a branch that represents your current development. You can update that external jar you depend on in your current development branch and it won't affect your currently deployed branch. This means you can have 1 build server constantly running your tests on both branches, and neither will need to worry that they share the same file system.

If you have any kind of branching going on, you run a much higher risk in hitting build issues if you depend on something outside what is committed to source control. If you have a test that needs to look for a file in a special location on your file system, there will be a problem the moment that file diverges between your branches.

If you must depend on some custom environment variables, prepare those environment variables within the build. Just like diverging files, it's entirely possible a separate branch will need to tweak those variables. Once you need to, your other branches will be hosed.

So, once again, once you've prepared your environment to be bulletproof, protect it vigorously. Don't let your build depend on anything outside what is committed to your source control repository, and your automated build server will thank you.

Friday, December 18, 2009

Protect Your Environment

Recently, I have been thinking of the environment a lot. Not global warming. Not the O-Zone disappearing. Not the ocean. Not the humpback whale or the spotted owl. I'm talking about your build environment. Your development environment. And, of course, your production environment.

These environments need protection just as much as our physical environment around us. Well, I suppose our physical environment should matter more, but as someone who lives on the computer, my computer environments matter a whole heck of a lot to me.

I'm here to tell you to set up an environment that automates just about everything you do, store it in your source control system, and then protect it vigorously. The moment someone strays and tries to let strands of wild growth choke your environment with custom tweaks, special path settings, and other such nonsense, trim those vines and get back to a clean garden. It's really not that hard.

I can't vouch for any fancy tools that manage this stuff automatically, because thus far I've stuck with living within my basic build environment. I've heard of tools that can manage your environment for you, but sometimes simple will work just as well. At my day job, we use Ant to run our builds, and little by little I've been molding our kudzu of a system into a manageable environment that requires little more than a subversion client, and a few additional packages. Ant can manage the classpath, so there's really no need to keep throwing jars into your shell's CLASSPATH variable.

My most recent addition was a simple custom Ant task to mimic Rail's environment setup. I created an environments directory and stored all the custom files that differ between our production environment, development environment, and any environment in between. It will hold custom properties files that are loaded at runtime, and Tomcat's context.xml so we don't have a local diff pointing to our development database. Within the environments directory is a directory for each environment, and the ant task will figure out which environment you are using, then copy over files from the appropriate environments directory to the correct location. This is much like Rail's environment.rb, with the different scripts in the environments directory.

A colleague recently set us up with Rails migrations, and I can't express how direly we needed this. It is important to version control all your database changes, but if you don't have a very orderly process to migrate between one release to the next, you are in for a world of hurt. Not knowing what has been run on your live database means you might miss something that could have drastic consequences with the code you are releasing along with it. Forget an important index and your queries will grind to a halt. Forget a key table, and your code could fail in an unexpected manner that might trigger other unintended failures, create corrupted data, or lose unrecoverable data.

By keeping your environment consistent, you can be more confident that deploying your new code will work exactly as you tested. By automating your environment, removing all of those special files you need to move to the right location or custom environment variables you need to tweak, you make it a lot easier to work within your team. You also can then bring in new colleagues and have a new development environment up and running for them faster.

The moment you tweak some kind of configuration that everyone in your team should do, automate it and put it in source control. If your tweak should only be in development or test, set up a simple environment switch in your build system, and grab the right file automatically. The production version and the development version should both be checked in.

So there... protect your environment. Who wants to be working in a jungle, anyways?

Wednesday, December 16, 2009

A Simple Ruby Pattern

By being a multi-paradigm language, Ruby provides numerous possible styles to write your programs with. I am a big fan of metaprogramming in Ruby, and one style strikes my fancy especially. By defining methods in your Class instances, your subclasses start to act like a domain specific language. You end up setting up a structural framework for how your subclasses behave, then declare the behaviors specific to each specific subclass.

To illustrate this, consider a simple calculator application. You could tackle such an application any number of ways, but we can come up with an interesting solution using class methods.

For starters, we need our base CalculatorBase class, which will provide the plumbing for dealing with input, handling if the input is numeric versus operations, and overall flow. I am not interested in these details for this post, so I will leave them as a homework problem for you to play with. Don't worry, it's fun!

First, your base calculator needs to expose a way to define operations:

class CalculatorBase
def self.operation(op, arity, &block)
define_method(op.to_sym) { |*args|
unless args.size == arity
raise "Wrong number of arguments"
end
block.call *args
}
end
end


From this, you can declaratively define what operations your calculator may support:

class Calculator < CalculatorBase
operation(:+, 2) { |x, y| x + y }
operation(:-, 2) { |x, y| x - y }
operation(:/, 2) { |x, y| x / y }
operation(:*, 2) { |x, y| x * y }
operation(:sin, 1) { |x| Math.sin x }
operation(:cos, 1) { |x| Math.cos x }
operation(:tan, 1) { |x| Math.tan x }
end


Now, you can invoke operations with ease:

calc = Calculator.new
calc.+ 2, 3
calc.sin 3.14159


However, I feel we can do better than this. There is a lot of repetition going on with the arity. To make our calculator implementation more domain specific, let's allow binary and unary operators to be defined easier:

class CalculatorBase
def self.operation(op, arity, &block)
define_method(op.to_sym) { |*args|
unless args.size == arity
raise "Wrong number of arguments"
end
block.call *args
}
end

def self.binary(op, &block)
operation op, 2, &block
end

def self.unary(op, &block)
operation op, 1, &block
end
end


With these new methods, we can make our operation declarations a bit easier:

class Calculator < CalculatorBase
binary(:+) { |x, y| x + y }
binary(:-) { |x, y| x - y }
binary(:/) { |x, y| x / y }
binary(:*) { |x, y| x * y }
unary(:sin) { |x| Math.sin x }
unary(:cos) { |x| Math.cos x }
unary(:tan) { |x| Math.tan x }
end


This isn't a particularly difficult approach in Ruby, but I really like the results whenever I am able to employ it. It can remove a lot of repetitive method declaration, and make your main class very clearly declare the behaviors it employs.

Of course, with great power comes great responsibility. It is easy to obfuscate the behavior you are creating with this pattern. Used appropriately, you can design an API and then speak the language of your domain in a much easier to comprehend fashion.

Sunday, December 13, 2009

Common Java Implementations

Java makes a lot of tasks more difficult than they should be. For example, checking if 2 objects differ can be cumbersome when you take into consideration that values could be null. Consider the following example implementing equals for a Name object (yes, some of that duplication could be simplified, but ignore that for now):

public class Name {
private String first;
private String middle;
private String last;

...

@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Name)) {
return false;
}

Name otherName = (Name) other;

if ((first == null) != (otherName.first == null) {
return false;
}

if ((middle == null) != (otherName.middle == null) {
return false;
}

if ((last == null) != (otherName.last == null) {
return false;
}

return first.equals(otherName.first) &&
middle.equals(otherName.middle) &&
last.equals(otherName.last);
}
}


Now consider the task of reading all the lines of a file:

File file = ...;
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
List<String> lines = new ArrayList<String>();

while (line != null) {
lines.add(line);
line = br.readLine();
}


Maybe you need to build a string that is a colon delimited list of the items in a list:

if (list.isEmpty()) {
return "";
}

String result = "";
result += list.get(0);

for (int i = 1; i < list.size(); i++) {
result += ":";
result += list.get(i);
}

return result;


Well, whenever you start cracking your knuckles, preparing to dig in and write a bit of code that you feel should be easier, stop. Take a deep breath. Consider who might have solved this problem first. It has likely been done before, so you can bank on another's implementation, with the benefit of it being thoroughly tested and likely highly performant.

In particular, the Apache Commons projects has a suite of useful tools to bank on. The equals example can be simplified to the following (thanks to the lang commons project):

@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Name)) {
return false;
}

Name otherName = (Name) other;
return new EqualsBuilder()
.append(first, otherName.first)
.append(middle, otherName.middle)
.append(last, otherName.last)
.isEquals();
}


While the reading of lines can be simplified to (thanks to the IO commons project):

File file = ...;
List<String> lines = (List<String>) FileUtils.readLines(file);


Besides the Apache Commons projects, you could try out the Google Collection Library to solve the colon delimited list:

return Joiner.on(":").join(list);


You may also want to browse Google's Guava Libraries project.

Whenever these libraries can be applied, you can be sure to cut the amount of code you are writing to a fraction of what it would have been, and likely a lot easier to understand and maintain.

Thursday, December 10, 2009

Don't make V1 TOO Crappy

Avery is a company that provides some... paper needs. I don't know all of what they provide, but I know they provide labels. I know this because my fiancée and I were printing out labels for our upcoming wedding. They provide an online tool that could be... very good. Instead, it is... so so.

They provide web tools to construct a PDF which can be printed on to your labels. This is an awesome idea because it is a very portable way to print to their paper products, and could provide highly customized behavior geared towards the type of paper you are printing to. Labels, in our case, could have some really cool software designed specifically around producing the exact labels you want on the specific Avery label product you purchased. If Avery wanted to be a leader, they could even support their leading competitor's products, so when you think of a good experience for your printing needs, you think Avery. This means you might be more likely go for the Avery products the next time you wanted to buy some labels, if they can leave that good of an impression on you. Nevermind the ad revenue they could rake in on top of that.

There is no reason this can't work on any browser with any operating system, right? Well, that is their first failure. The tool (which seemed to be primarily built with flash) wouldn't work on Chrome or Firefox in Ubuntu. I see no compelling reason why it had to be built with Flash, except that it probably was easier to develop their customized UI. Well, I don't believe Flash really gains you much there, but I can understand the thinking that it does. Regardless, some of the controls just failed to respond in my browsers. Namely, a checkbox to toggle the first row in a mail merge as header names vs a separate data row wouldn't respond. Also, the button to add a new span of text on the label didn't respond. Ultimately, I was forced to use IE within my Windows VM, as disgusting as that was. Firefox might have worked on Windows (and maybe even Chrome), but after 2 failed browser attempts, I wanted to go to the crappiest browser that too many unskilled developers still seem to target exclusively.

Ok, force me to use a shitty browser to get my work done... that's a huge mark against you, but if the rest of the user experience is just mind blowingly awesome, I can forgive you. But seriously... I have to have a blown mind by the time I'm done for me to forgive you. It's just too easy these days to write cross browser HTML and JavaScript to excuse the lack of portability. This is not an application that screams the need for Flash, so I think it's an indication of a lack of talent and creativity that they resorted to Flash.

Moving on, I ran across another bug that showed the lack of polish they put into this product. They have a nice mail merge feature that allowed me to upload an Excel spreadsheet and use the rows as addresses. This is a must have for printing labels, but also one of those features that makes you happy to be using a computer instead of doing this stuff before our digital age, like attempting homebrew calligraphy with a ballpoint pen. So, they had a nice feature that I already mentioned. You could mark the first row as the row specifying your field names, effectively starting your data on the second row. Neat! It even worked! Except... for our recent batch of labels, when selecting fields to place in the label, only the first field was showing, and truncated as "Mr." That's odd. We tried dropping the header row, and the problem still showed up. I guess I should add that the first column value of the first row was something like "Mr. & Mrs. John Doe." It dawned on me that maybe these mindless developers were so bad that a simple & character could screw up the mail merge. I moved the row down and put in a more innocuous row at the top. Sure enough, it worked smoothly! So, let me get this straight... a mail merge that could have completely arbitrary data in it breaks down because of a simple & character???!?!? I shudder at the thought of what security holes might be present in this application.

Ok, I have saved by far the most egregious issue I have with their application for last. Their login process. Now, I can't for the life of me understand why they need any of my information to let me generate a PDF. However, they had multiple required fields, including my name and email. Why do you, Avery, need this information to construct a PDF to help me utilize your real product? It baffles me. Well, I gave the information, and then had to go back and start again due to some of the issues above. I figured this process had implicitly registered me, since the form had looked like a registration form. When I went back and attempted to log in, I discovered that this was not the case at all. That irked me, so I decided to register. And, FYI, the registration form looked exactly like the form to just use their web tools directly... just with an added password field. I registered and then clicked the link to get back to printing labels, and guess what? I got the form again to get my name and email to start the label making process again! Are you KIDDING ME?!?!?!?!!!!!

In what could have been an amazing experience, Avery thoroughly dashed my hopes that more companies are starting to understand that cross platform web tools are the future. Instead of being a leader in the specialized paper printing business, they have made me shudder at the incompetent developers that they likely hired to do this job. There were nuggets of a really cool product, so there must be some smart people there... but they are likely drowning from a few really bad apples.

I think this kind of disproves Jeff Atwood's recent post that you should release a crappy version 1 and iterate. Or at least, it reinforces the thought that he included that you shouldn't release total crap for version 1. I guess Avery could redeem themselves in my view if they are iterating and actually listening to good feedback. If I come back in a couple months, and all of these issues are somehow tackled... I could forgive these transgressions. I seriously doubt it will be the case though.

I think Avery is stepping in the right direction with their online tools. They have a lot of potential there. Unfortunately, their execution makes me embarrassed as a fellow web developer.

Friday, December 4, 2009

A Few Worthy Bytes

Bandwidth is a lot cheaper now than it was 10 years ago. Dialup is a dying breed. So please, please, please don't craft your HTML to save every last byte. It is a lot more worthwhile to make your code readable and immediately intuitive than to prevent an extra 10 bytes from going to the user. If you find that you are causing huge downloads of extra HTML, and it is becoming an issue based on real statistics... then start looking into addressing the issue.

For example, consider the following snippet:

<a href="/path/elsewhere"><%
if @condition
%>True text<%
else
%>False text<%
end
%></a>


It may not look that bad alone, but when you try to save every byte, the result months from now will be a garbled mess that is difficult to comprehend. Instead, ignore those extra bytes and produce the following:

<a href="/path/elsewhere">
<% if @condition %>
True text
<% else %>
False text
<% end %>
</a>


If outputting all that extra useless whitespace makes you feel too icky, Rails has an option for you. If you close your scriptlet tag with a dash, as "-%>", Rails will strip some of the whitespace.

<a href="/path/elsewhere">
<% if @condition -%>
True text
<% else -%>
False text
<% end -%>
</a>


Just remember that someone has to maintain the code, and making code more difficult to comprehend will end up costing you more than the bandwidth you saved.

Tuesday, November 24, 2009

Closures for Java 7: DOA

To start off today's (probably) brief post, I want to quote Stephen Colebourne's blog:

JDK 7 closures will not have control-invocation statements as a goal, nor will it have non-local returns. He also indicated that access to non-final variables was unlikely. Beyond this, there wasn't much detail on semantics, nor do I believe that there has been much consideration of semantics yet.


Now, I can't vouch for his facts, but it seems accurate, so I am going forward with the assumption that I'm getting it from the horse's mouth.

That said, I want to state what closures in Java 7 will be if they are implemented as stated above. Can you guess? Yeah... sugar syntax for anonymous classes.

As a Java developer, I don't want to complain. Anonymous classes are a major pain in the ass. Any time I attempt some functional programming with them, I always look back and think... that would be so much more elegant with a foreach loop, or some such thing. Anonymous classes are a lot of syntax for very little meat. Getting rid of the painful parts of that syntax will definitely be a good thing.

As a Ruby developer, these so-called "closures" are a laughing stock. Can anyone really claim these are actually closures? Let's just stop kidding ourselves and call them elegant anonymous classes.

Without control-invocation statements or non-local returns, you can't turn a foreach into a method call with a closure. Without access to non-final variables, you have to either move the variable into the class, wrap it in an object, or do the horrible 1 element array trick. You know... construct a 1 length final array which you can then both get and set the element from within the anonymous inner class... it blows.

If my vote matters, it is for waiting till Java 8 and doing closures right, or giving us a little meat for Java 7 closures. Bare minimum, non-final variables have to be accessible.

Sunday, November 22, 2009

Smart XML Processing with Regexes

Recently, Jeff Atwood wrote about parsing HTML with regular expressions. I want to speak about it briefly, because I came across this issue last week. I gathered from his post that the lesson is to consider your options with an open mind, and only block a possible solution if you really understand the alternatives. Use facts and knowledge to choose your implementation details, not superstition and theoretical best practices. Best practices usually are created for a reason, but that's not to say there's never a reason to turn your head on them.

This post hit home with me because I had an XML file to parse that was over a gigabyte. From this XML file, I needed a very small handful of the data, and it was very regular XML. XML parsing is a solved problem, but most XML libraries I've used would easily choke on such a file.

Instead of even considering attempting to process this data with a normal XML processor, I wrote a simple Ruby script to extract the information. It looped over each line, looking for key parts of the data with lines like:

if line["<expectedTag>"]
# deal with this tag
end


Then, I processed the key tags and data I was looking for with regular expressions, such as:

data = line[/<expectedTag>(.+)</expectedTag>/, 1]


The above was done within the if blocks. The key point being regexes would have been too slow alone, so I used the simple indexer method to quickly determine if the line contained something that mattered to me. Then I used the regex to pull the data that I actually wanted.

Can you write XML to break my processing? Of course! The question is... does it matter? And that answer was no. I only need to process this data once, maybe another time sometime in the distant future, but the XML is so regular that I know it will work for all the data. On top of this, if I missed some data, it wouldn't matter in the slightest for my purposes. So, in short, proper XML processing would have severely slowed me down (ignoring all lines that don't contain a keyword is much faster), and it would have produced no real benefit.

I ended up processing all the data in little over a minute or two, and I considered it a huge success. Over a gigabyte of XML to process seemed a rather daunting task initially!

Wednesday, November 11, 2009

Cautious Development

One of the most appealing features of Test Driven Development for me is that it helps you write code that actually works when you are done. If you are testing at each step, you end up with code that works for all those features that you explicitly tested. This is not to say you will end up with bug free code, of course. Nobody but a pointy haired boss would expect that.

All too often, I see code that is supposedly done, but a cursory run through some simple examples shows earth shattering bugs. Bugs where the basic features being implemented don't even work. What possesses a developer to think something is done when it hasn't been played with for a while, showing some level of completion? I guess we all fall into the trap of simplistic changes that can't possibly cause a problem, only to have some bug crop up specifically because we aren't looking. Sometimes some manual (or even automated) tests would be so tedious to set up that it just doesn't seem worth the effort. But I've seen cases where it's clear the code was not very carefully crafted in any regard, with no reason that it couldn't have been done better.

The most absurd example came from someone I helped interview quite a while ago. I distinctly remember going in and running the beginnings of the code with him. I put in some input and saw some output... all was good. When I returned a while later, the IDE still showed the exact session we had run as much as an hour earlier. Not only did the code not even compile, it had no hope of working even if we could trick the compiler into giving us a green light. Is it a rare quality among developers to actually play with the code as you go along?

I'm not saying you need to exercise the code in a particular manner, just that you exercise it in any manner. Run the code at every step, playing with the new features you are working on, and sanity testing some older features. Write it test first and watch new tests succeed as older tests continue to succeed. Hell, even take a waterfall approach with a big bang batch of code, then furiously cycle through short runs to find and fix a bug. I don't care, as long as when you say you are done, it isn't trivial to find a bug in the code.

Unsurprisingly, I'm also a fan of writing your code in the most cautious manner possible. Some developers seem to like to go in to old code and just run wild in it, tearing things out and replacing them left and right with no regard or respect for something that might be doing the job well, or at least well enough. Sometimes a piece of code can prove to be so obscure and hard to maintain (or even understand) that it makes little sense but to throw it out and start from scratch. That should be more rare than common, though.

When it comes to refactoring, I like to go in and be very careful that the new code preserves equivalent functionality, especially if the code isn't covered by a good suite of tests. Don't go in and replace a whole class with a new class that does the same thing in a way you like better. Instead, move code around and massage it into the shape you need, slowly but surely preparing it for the new feature you need to add. Continually ask yourself if the shape of the code does exactly what was being done before (unless of course you discover a bug). Pretend that if you introduce a new bug as a result of your changes, the entire company and all the users will come and yell at you and deride you for making such a mistake. Worry for every millisecond that you might be making a breaking change.

Care for your code. Envision the code is your lover. Would you do a single thing that might hurt your lover's feelings? Would you want her to stub her toe because you moved the table to the wrong location? Then don't make sweeping changes without being extremely cautious, because you will only guarantee to stub your code's toes. If you treat your code right, she will only get more beautiful, while learning new and exotic tricks.

Sunday, October 12, 2008

Till Death do we Rewrite

It's been a while since it was written, but I recently read an interesting article from Joel Spolsky. It's from 2000, but it is of course still very relevant.

The article was about rewriting code, something he argues you should never do. It might be more fun and appealing to play devil's advocate, but I can't for this one. Joel is dead on here.

In my last job I was dealing with GUI code primarily. There were a few of us working on this section of the code, so it was by no means all my own work. One particular component of it was written by someone else who ended up moving on to another part of the project, so me and a few others inherited the work.

There came a time to expand on this component, and so I looked over what was done. It seemed somewhat awkwardly implemented, and I felt I could do a lot better if I started from scratch. There were events being raised and passed on 3 levels deep in the object hierarchy for no apparent reason, and the object structure itself seemed a bit awkward. It also got a bit slow under certain circumstances. Thus, I plowed ahead with a rewrite.

I started out strong. I had objects that correlated logically with what was being displayed on the screen. I had a simple structure that seemed a lot clearer and cleaner to me. It was working, and it seemed to even be faster. I was proud of what I had created (at least, at the time I was).

Then time went on and the GUI got more complicated. It sprouted the hairs that Joel talks of, and started getting slow for no apparent reason (but in different ways from the original implementation). All in all, the end result started looking a lot more like what had been there than I liked to admit.

The rewrite wasn't a total failure... it worked, and some of the details had definitely been improved, but at the cost of some new hairs that I would rather go back and fix. However, in retrospect, it would have been a much better idea to just dig in with the existing code and salvage what I could, refactoring what really needed improvement. I walked away with a valuable lesson though... whenever you want to rewrite code... don't. What is already there can work if you give it a chance. Refactor what doesn't work, and make the unclear sections more clear.

Learning to resist the urge to totally rewrite code is an important lesson I needed in order to become a better programmer.

Thursday, October 9, 2008

Please Hold on the Interfaces

I just got my first Notable Question badge over on stackoverflow.com for what seemed to turn into a rather controversial question. At the time, I was just ranting based on a question I had just read where all the answers suggested the use of an interface, when it didn't really seem to need one. Even more egregious, the interface was basically being proposed just to support testing.

To spare you a little reading, the basic premise of my question was: interfaces are overused, and it sucks when they are being overused, so what is it I'm missing, if anything?

This got some people to go NUTS over it! I mean, literally these people went wildly crazy, spouting nonsense... listen to this one, which was probably one of the worst responses I saw:

An issue with favouring mocking (or any kind of runtime substition) through subclassing, rather than through an interface, is that you can only override the behaviour of virtual members.

Invoking a virtual member requires an additional level of indirection via a Vtable and is slower than a final member. Whereas using an interface adds a compile-time overhead, but using virtual members adds a runtime overhead to every member invocation.

Surely, adding an interface **just to support mocking** is far preferable to slowing down your entire app **just to suport mocking**?

My preference, therefore, is to favour 'final by default'.



Talk about premature optimization!!!! This guy wants to avoid polymorphism because of the runtime costs?!?!? I can't believe how STUPID people can get sometimes! I mean, seriously! I try not to get angry when I'm on the Internet, because flame wars and trolling gets us nowhere, but c'mon now. A v-table call is going to be... what... nanoseconds? Even faster? So small we can't even reliably measure it??? And he thinks he has a net gain by avoiding that cost? I sure wouldn't want to be the one maintaining HIS code!

OK, I'm getting off topic. Interfaces. Those things that pretend to be a class, but have no details whatsoever. I don't mind them. Sometimes they can be quite helpful. However, like all tools, we must stop and analyze why we are going to use the tool, and what will we gain by doing it. If you pound on a screw with a hammer, you might just get it in there, but did you go about it the best way?

There are times when interfaces make a lot more sense in places they don't seem to belong, such as perhaps frameworks... though this guy rightfully pointed out that they also lock you in and restrict change, especially in frameworks (where you can't control who has implemented it).

So here's my biggest beef with interfaces: using one when you have a single implementation class.

That's it. That's the single most spine-curling, eye-gouging use of interfaces that will make me want to vomit all over you if you suggest it.

If you are a lover of interfaces, this may come as shocking news (as I sadly found out). Why is it so bad? You get to increase testability, right? You make your class more extensible, right? You are programming to an interface, right?

WRONG! No, no, no, no.... NO NO NO!

Testability

First of all, testability has nothing to do with whether you have an interface or not. It has to do with whether or not the dependencies you have in your class can be mocked out and altered so that you can ensure that the class works properly regardless of what those dependencies spew at you.

For example, let's say you have an object that represents a customer, which is represented in the database. Perhaps one of the worst things you can do is load the data for that object from the database from within the constructor. At this point, you can't get around constructing your object without depending on the database. Now, if you want to write a test for a DIFFERENT class that uses this customer object, you all of a sudden have to have the database up and running. This is bad because it makes the test a lot more complicated than it needs to be.

Now, if you are in the Interface Camp, you might be thinking... hah! If you define an interface for that class, you can get around that dependency! This is true, but it's also the easy way out. Singletons are also the easy way out to a lot of problems, but you don't hear many people clamoring for singletons everywhere, do you? The easy way out is oftentimes NOT the clean or best way out. Instead of shrouding your class in an evil interface, just move the database initialization to a protected method that the constructor calls. Now you can override the protected method in subclasses or mock classes and no longer depend on the database!

Extensibility...?

I just don't understand why people think classes are less extensible than interfaces. It just isn't true, damnit!! I've been extending classes left and right when I see the need, and I have never had a problem. The trick is, again, to avoid dependencies.

If you are doing something that can't be changed in a subclass, you might be doing something wrong. The constructor is the first place to look... is there behavior in there that does something that might be unwanted in an alternate version of this class? Is there a static initializer that is doing something fundamental to the class that can't be changed in a subclass? As long as you have only virtual methods (believe me, the "performance hit" is worth it... and it's why I love Java's default virtual and hate C#'s default final), and your constructors and static initializers are clean, you can reimplement the entire class as if it had been an interface all along! It's really not that hard, and if you are active with Test Driven Development, you will find the classes often come out that way anyways.

Programming to an INTERFACE....?!?!

Someone else said it better. I don't remember who, and I don't remember where. What do I look like, google? Find it for your own damn self! Well... the gist is, "programming to an interface" does not mean literally to a programming language construct called an interface... it means programming to a contract between you and users of your class... i.e. the publicly visible methods, fields and constructors agreed upon between you and clients of your class.

Just because "interface" is a keyword in some programming languages, doesn't mean we can't speak about "interface" as an English word used to describe what we are exposing.

Appropriate Uses??

I'm not going to lay out a bunch of rules on when you should use an interface. Deciding what tool to solve a particular problem is often somewhat of an art more than an algorithm, so you really have to look at the problem and just decide for yourself. You may end up using interfaces in an inappropriate time... but hey, we all make mistakes! Refactor it when you find a better way... you got all those tests to deal with it, right?

Without going into too much detail, I think a good rule of thumb for when to use an interface effectively is to use it when the thing you are trying to build doesn't lend itself to a default implementation, or you literally HAVE to do it... such as the case when you absolutely need to extend 2 classes (pick one, and extract an interface). However, there can be ways around needing the interface in these cases, but if the interface is cleaner, go for it.

You WILL Regret it Later!

No, you won't, but some claim you will, like this guy:

Sure, sometimes you may not ever have an alternate implementation of ISomeFoo in which case it might have been a waste for that particular component. But if you ever DO need to have an alternate implementation, going and changing those 50 references to concrete PetrolSomeFoo to concrete HydrogenSomeFoo will hurt really bad, especially if someone of the changes involve other applications or integration scenarios.

So, my argument is to let the IDE do the work for you. Extracting an interface and replacing all references is not all that hard of a task, especially given the help of a good IDE. If you are developing a framework where you don't control client code... this is one of the few cases where more interfaces might make sense, unless you have the balls to break backwards compatibility. If you have the ability to only use a tool when you need it, I say save on using that tool unless it really solves your immediate problem cleaner than other solutions.

Finish Already!

So the next time you reach for the interface keyword, stop and consider to yourself... is this really the best solution? Am I really solving this problem cleanly and elegantly with interfaces, or am I just hacking around a problem without considering how else I might solve it?

Monday, July 28, 2008

Why Java Generics Suck

When I first saw Java's Generics, I thought it was a pretty neat addition (rather harsh syntax, but effective). You get stronger type safety without all the extra casts. Less code with less room for mistakes, right? Well, yes and no. The problem is, Sun wanted to add this new feature, but at the same time preserve bytecode compatibility. There are probably a lot of reasons that maintaining bytecode compatibility is a good thing, but I just don't buy it.

So, what am I talking about you ask? Good question. The way Generics are implemented is via a thing called Type Erasure. What this essentially means is that the type information is there only for the compiler. So, if you have a List<String>, you don't ACTUALLY have a list of strings. You have a List that will only let you store and retrieve strings, but ONLY as long as you know the type of that list. I will get to an example in a little bit. My best guess at why Sun did this is they wanted to add this neat feature that C# had and C++ had, but at the same time they didn't want to cause upgrade problems where clients of your code MUST be using the Java 1.5 runtime. Except, if you use any of the new API, your clients are going to have to upgrade to Java 1.5 anyways, so it seems like a myth that they are ACTUALLY benefiting anyone by being backwards compatible. By trying to appease 2 crowds (those wanting more features and those wanting to be able to run on old runtimes), they ended up creating a bit of a Frankenstein's Monster in the process.

So if that garbled mess of a paragraph didn't help you understand the problem (which it probably didn't... I was really just ranting), then hopefully a concrete example will help.

Have you ever seen the warning "Type safety: The cast from Object to List is actually checking against the erased type List" or something like it? You can get it from the following code:

public static void storeInt(Object object, int value) {
List<Integer> list = (List<Integer>) object;
list.add(value);
}

What this means is that you tried to take an object without Generic type information (Object for example), and you tried to extract the Generic type information from it (Integer)... except that information was erased the moment you stored your list into a reference of type Object. Why? Because in order to preserve backwards compatibility, the generic type of Integer is not ACTUALLY available at runtime. This means you can end up recasting your list to the wrong generic type, and add elements of the wrong type, which can later cause a ClassCastException. Consider the following code:

public static void storeString(Object object, String value) {
List<String> list = (List<String>) object;
list.add(value);
}

public static void storeInt(Object object, int value) {
List<Integer> list = (List<Integer>) object;
list.add(value);
}

public static void printList(Object object) {
List<?> list = (List<?>) object;
for (Object value : list) {
System.out.println(value);
}
}

public static void main(String[] args) {
List<String> list = new ArrayList<String>();
storeString(list, "Hello World");
storeInt(list, 1);
printList(list);
}

The above code will not only compile, it will also print 2 lines, the first saying "Hello World" the second saying "1"... even though we have clearly violated our initial list of strings and stored an integer in there. However, let's add some more code. After the printList call in the main method, try:

for (String value : list) {
System.out.println(value);
}

Now you will finally see the runtime error you might have been expecting in the previous example. This time you will see "Hello World" followed by "1" followed by "Hello World" followed by a ClassCastException. This is because Java is trying to take the "1" and put it in the String value reference... but it's not a String, so we have a casting problem! If sun had implemented Generics right (which probably would have meant byte code incompatibility with 1.4), then the first time you tried to cast that list of strings as a list of integers, you would have gotten a ClassCastException. Furthermore you would have been able to do things like this:

public static <T> T createAndStore(List<T> list) {
T value = new T();
list.add(value);
return value;
}

and this:

public static <T> T[] toArray(List<T> list) {
T[] array = new T[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
return array;
}

But with type erasure those 2 examples are impossible, because the type is unknown at runtime.

You may think that I am just ranting about these and that the issues never come up, but I assure you they do come up. If you are working with any legacy code or APIs that were not built when Generics were around and did not upgrade to use Generics (or were built when they were around, but the author(s) didn't think to use them)... or if Generics just can't solve the problem that a simple list of Objects can, then there can be issues.

Case in point: servlets. Take a look at the servlet API, particularly HttpSession's getAttribute method. I can only store and retrieve Objects, which makes sense. I should be able to store anything I want in the Session. However, the moment I store an object with Generic type in there... especially one that needs to be modified, I have thrown type safety out the window.

Let's say I store a list of strings in the session, and I want to add a string to that list periodically throughout my user's session. This doesn't seem so far fetched, right? Well, now how do you suppose to add items to that list once you have removed the String generic type information?

public static void addString(Object object, String value) {
List<String> list = (List<String>) object;
list.add(value);
}

causes a warning at the casting time like we discussed before.

public static void addString(Object object, String value) {
List list = (List) object;
list.add(value);
}

also causes a warning, this time at the point where we call add... because Java thinks we should be using Generics... after all, they spent so much time designing the system, you should always use it!

public static void addString(Object object, String value) {
List<?> list = (List<?>) object;
list.add(value);
}

causes an actual compiler error on the add call... because Java can't give you any guarantees that you are safely calling add with the correct type, so they just don't let you.

The solution? Well, you have to just use the SuppressWarnings annotation on the method where you want to add that string! Seems like a hack to me, but maybe you can live with that. Personally, I would rather just ditch Java and go use Ruby. None of this is even remotely an issue when you go dynamic.