Wednesday, December 31, 2008

Things to dislike about Java

Back in August I started working with Java the majority of the time. I still do a bit of Ruby, but the vast majority of my work these days is in Java. Java is good for a lot of reasons, but that is absolutely not what this post is about. This post is, in no particular order, the things about Java that I really dislike.

Closed Classes
I'm not sure if there's a term for this, but it's the opposite of what Ruby calls Open Classes. Open Classes allow you to define or redefine behavior on any class at any time. Java does not give me this ability. Let's look at a simple example, say I want to define a method that checks to see if a string is null or empty. In a language with Open Classes you can add behavior directly to the String class, so you could check to see if a string is null or empty by asking the string itself.

string.empty?

In an Object Oriented language, where objects are supposed to have appropriate behavior, I like having the ability to add the correct behavior to the correct class.

In Java, I'm stuck doing something very different. I could import some class defined in some library that has way more than I actually need, or, more likely, I'll just define my own StringUtils class and create a static method. In Java 6 I can static import this method, which makes my code procedural, joy.

If you are in the .net camp, don't laugh too loud. Your extension methods are flawed. Until you can override existing behavior, you're only halfway to the solution.

Lack of Closures, Blocks, Anonymous Methods
Whenever I manipulate a list of items I find Java severely lacking. In Clojure I can double each element in an array by simply calling the map method with an anonymous function and a list.

(map #(* % 2) [1 2 3])

In Java I'm stuck with iterating over the array, and adding the results to a temporary collection that is appended to with each iteration. I find that ugly, but it hardly compares to the absolute disgust I have for classes like Comparable and Runnable. An anonymous class instance that has one method is an obvious sign that the language is severely lacking in the area of closures, blocks, or anonymous methods.

Army of NNPPs
Java is currently the "one language to rule them all". This brings about several problems, one of which is the number of terrible programmers writing Java code. I'm lucky enough to work for a company that wants to "build the best software development teams in the world", so I don't work with a single person that writes code I find ugly. Unfortunately, that doesn't save me from the Java NNPP zombie army. Java NNPPs flood the forums and mailing lists with elementary questions and incorrect answers. The amount of signal to noise is so low that I find myself unsubscribing from every public mailing list, and avoiding all Java related forums. It's a shame that I generally have to stick to private mailing lists just to ensure I receive relevant answers.

Literal Arrays & Hashes
Arrays and Hashes are used so frequently, there's really no excuse for not having a literal syntax. In production code this is somewhat painful, but it really shows up in tests. Java does have a few solutions, two of them can be found in the following example.

asList(1, 2, 3, 4)
new Integer[]
{1, 2, 3, 4}

While these do offer "options" they both end up causing problems. The asList method works for about 75% of situations, but leaves me disappointed at least 25% of the time. Far too often there seems to be a method that doesn't like the return value of asList; therefore, I end up doing something significantly uglier to build a "correct" collection. The second example, the traditional Java array also works, but it's ugly to create and often to limited to work effectively with.

Command Line Execution for Snippets of Code
Sometimes you need to do something quick and simple. A command line interface (Ruby's IRB, Clojure's REPL) makes you more effective by seconds or minutes, millions of times a year. That wasted time adds up.

Java (the programming language) is so amazingly verbose (I'm talking about Java, the programming language)
Java forces me to repeat things all the time.

public class NewOrderHandler {
public void onNewOrder(NewOrder newOrder) {
// handle new order
}
}

In 2 lines of code I managed to type "NewOrder" 4 times. Even with a fancy IDE this gets very tedious. When writing Java code I don't actually write anything, I just keep hitting [Ctrl + space] and [Alt + Enter] all day long. When I'm writing code this tends to not be such a problem. I use IntelliJ for all my Java programming and I'm comfortable admitting that I can write Java code as fast as I was writing Ruby code.

The problem is, I don't spend all my time writing code. I spend a fair amount of my time reading code, code someone else on my team wrote, or code I wrote a few months ago. While I can write Java (or at least [Ctrl + Space] Java) as fast as I can write Ruby, it takes me at least 3 times as long to digest the responsibilities of a class written in Java as compared to Ruby.

These days I spend far more time trying to digest a class that takes 4 other classes as dependencies and each of those classes combine with the original class to solve one problem. Unfortunately it takes so much code to get something done that the simple behavior had to be split among 5 classes. To make matters worse everything has to be injected via the constructor because it's the only reasonable way to write testable software. So I end up reading pages of code to understand how each piece collaborates to do one simple task, awesome.

Extensive Tool Support Raises the Barrier of Entry for Tool Builders
I find the Java testing frameworks, much like Java itself, to be a generation behind. There have been steps forward elsewhere and the Java testing frameworks haven't yet caught up. I'm not one for complaining without providing a solution, so I started toying with building a testing framework. Does it integrate with IntelliJ? Of course not. Does it integrate with Eclipse? Absolutely not. Would anyone use it without integration? Emphatic No.

So now it's not good enough to create a good library, now I have to learn about IDEs also. Or (in my case anyway), drop the idea for more interesting pursuits, like finding the language I can replace Java with.

Conclusion
Java's not all bad. In fact, it might be the best tool for the work I'm doing these days. It's definitely tops in the areas that I need to be successful overall. But, I really do miss the things listed here, and all the other things that I've forgotten to write about but consistently swear about at work.

Happy New Year! Here's to a year where I find a suitable replacement for Java.

Tuesday, December 09, 2008

Targeted Languages

The vast majority of actively evolving business software is written in Java these days. Java has long enjoyed the title of One Language to Rule Them All. However, in a previous post, The Next Big Language, I mention that I'm skeptical that there will be one language that is perfect for solving all possible problems in the future.

I might be overestimating the speed at which our profession is maturing. One of the reasons Java became the enterprise standard was because the wrong people were making decisions based on inadequate information and swarms of terrible programmers. I like to believe that we're moving away from those days, but then again, we definitely still have far too many NNPPs that need to be encouraged to find other employment. However, I do think it's inevitable that we move to languages targeted at specific domains and problems eventually.

We've already taken the first step. Games are a form of business software. Games are consumer products. However, game development has never been dominated by Java. I won't pretend to know about the game industry, but from what I hear it's been largely dominated by C++. However, these days Lua has enjoyed great popularity in the videogames industry.

The game industry has been using the right tool for the job for some time; however, other business are also starting to catch on. Many companies are using Ruby and Rails to build websites. There's no question that having a good group of programmers building your website using Ruby and Rails can provide a significant competitive advantage. Erlang is another language that targets a specific class of applications, and it provides huge advantages over the alternatives for those applications.

I think targeted languages raise some new interesting questions.

For the professional software developer, targeted languages may make it harder to switch domains. These days it's easy to get a job doing Java development in insurance, banking, advertising, and many other domains. If in the future all the banks are using a functional language focused on low-latency, you may find it harder to make the switch to an advertising agency with a shop that's using an object oriented dynamic language. It may not be long before selecting a language implies selecting a domain as well.

There will be implications for firms also. The pools from which companies hire from will get much smaller. It's very hard to hire a good Java developer these days, imagine what the picture is going to look like when there are 5-7 targeted languages that are widely accepted and the developer pool is split 5-7 ways.

There will also be questions about how many languages your organization will support. If you're a bank and you write your trading applications using the best language for the job, would you allow the intranet dev team to use a completely different language?

Companies are already facing these questions. At DRW Trading we use C#, Java, C++, Python, Ruby, Perl, etc. I hear that Google only allows C++, Java, Python, and Javascript. There's definitely a balance between leveraging existing knowledge and using the right tool for the job. However, finding that balance isn't an easy task.

Like it or not, we're headed towards more targeted languages. It's probably worth considering the implications sooner rather than later.

Wednesday, November 19, 2008

Ubiquitous Assertion Syntax

One thing that really bothers me about testing is having various different assertion syntaxes. Take a look at the following JUnit examples. (don't worry, I'll be picking on Ruby and .net frameworks as well)

@Test public void simpleAdd() {
assertEquals(2, 1+1);
}

@Test(expected= IndexOutOfBoundsException.class) public void empty() {
new ArrayList<Object>().get(0);
}

In both tests I want to verify something; however the two tests use different mechanisms for verification. This adds pain for anyone reading or maintaining the test. When determining what a test is verifying you need to look for assertions as well as expected exceptions in the annotation.

When you start adding behavior based tests the situation gets even worse.

Mockery context = new Mockery();

@Test public void simpleAdd() {
assertEquals(2, 1+1);
}

@Test(expected= IndexOutOfBoundsException.class) public void empty() {
new ArrayList<Object>().get(0);
}

@Test public void forWorksCorrectly() {
final List<Integer> list = context.mock(List.class);

context.checking(new Expectations() {{
one(list).add(1);
one(list).add(2);
}});

for (int i=1; i < 3; i++) {
list.add(i);
}
}

Testing 1.0
3 different tests, 3 different ways to verify your code does what you expect it to. To make matters worse the mock expectations live in the body of the test, so there's no guarantee that when looking for assertions you only need to look at the last few lines of the test. Every time you encounter a test you must spend time looking at the test, top to bottom, and determine what is actually being tested.

The tests above are simple, it's a much bigger problem when a test uses a few different forms of verification.

Mockery context = new Mockery();

@Test(expected= IndexOutOfBoundsException.class) public void terribleTest() {
final List<Integer> original = new ArrayList<Integer>(asList(1, 2));
assertEquals(2, original.size());
final List<Integer> list = context.mock(List.class);

context.checking(new Expectations() {{
one(list).add(1);
one(list).add(2);
}});

for (Integer anOriginal : original) {
list.add(anOriginal);
}

original.clear();
original.get(0);
}

Okay, it would be terrible to run into a test that bad. You might work with people who are smart enough not to do such a thing, but it's very common to see tests that have both assertions and methods that are mocked. You may not consider mocked methods to be a form of verification, but if one of those methods isn't called as you specified it should be called, your test will fail. If it can cause your test to fail, it's a form of verification in my book.

In Java, there are at least 3 ways to define expected behavior, and often a test mixes more than one. This is not a good situation for a test reader or maintainer.

In the Ruby and .net worlds, the story isn't much better. The state based assertions are specified differently than the behavior based assertions; however, both Ruby and .net have a superior way of handling expected exceptions: assert_raises and Assert.Throws.

Below are similar tests in test/unit with mocha (Ruby), with an example of assert_raises for handling the expected exception.

def testState
assert_equal 2, 1+1
end

def testError
assert_raises(NoMethodError) { [].not_a_method }
end

def testBehavior
array = []
array.expects(:<<).with(1)
array.expects(:<<).with(2)
[1, 2].each do |number|
array << number
end
end

And, for the .net crowd, here's the NUnit + NMock version of the 3 types of tests. As previously mentioned, NUnit provides an assertion for expecting exceptions, but there's still a mismatch between the state based and behavior based assertions. (full disclosure, I don't have Visual Studio running on my Mac, so if there's a typo, forgive me)

private Mockery mocks = new Mockery();

[Test]
public void Add()
{
Assert.AreEqual(2, 1+1);
}

[Test]
public void Raise()
{
Assert.Throws<ArgumentException>(delegate { throw new ArgumentException() } );
}

[Test]
public void Behavior()
{
IList list = mocks.NewMock<IList>();

Expect.Once.On(list).Method("Add").With(1);
Expect.Once.On(list).Method("Add").With(2);

for (int i=1; i < 3; i++) {
list.Add(i);
}
mocks.VerifyAllExpectationsHaveBeenMet();
}

Testing 2.0
In each language there have been steps forward. Both Java and C# have moved in the right direction regarding placement of behavior based expectations. Ruby still suffers from setup placement of mock expectations, but at least the behavior based expectations follow the same assertion syntax that the state based assertions use.

In Java, the Mockito framework represents a step in the right direction, moving the mock expectations to the end of the test.

@Test public void forRevisited() {
List list = mock(List.class);

for (int i=1; i < 3; i++) {
list.add(i);
}

verify(list).add(1);
verify(list).add(2);
}

Likewise, in .net, Rhino Mocks allows you to use "Arrange, Act, Assert Syntax (AAA)". The result of AAA is (hopefully) all of your tests put their assertions at the end.

public void ForRevisited()
{
var list = MockRepository.GenerateStub<List>();

for (int i=1; i < 3; i++) {
list.Add(i);
}

list.AssertWasCalled( x => x.Add(1));
list.AssertWasCalled( x => x.Add(2));
}

These steps are good for the big two (Java & C#); however, I'd say they are still a bit too far away from ubiquitous assertion syntax for my taste.

RSpec represents forward progress in the Ruby community.

it "should test state" do
2.should == 1+1
end

it "should test an error" do
lambda { [].not_a_method }.should raise_error(NoMethodError)
end

it "should test behavior" do
array = []
array.should_receive(:<<).with(1)
array.should_receive(:<<).with(2)
[1, 2].each do |number|
array << number
end
end

RSpec does a good job of starting all their assertions with "should", (almost?) to a fault. It's not surprising that RSpec was able to somewhat unify the syntax, since the testing framework provides the ability to write both state based and behavior based tests. Looking at the tests you can focus on scanning for the word "should" when looking for what's being tested.

Unfortunately the unified "should" syntax results in possibly the ugliest assertion ever: lambda {…}.should raise_error(Exception). And, as I previously stated RSpec still suffers from setup placement of the mock expectation "should" methods. Perhaps RSpec could benefit from AAA or some type of test spy (example implementation available on pastie.org).

# this doesn't work, but maybe it should....

it "should test behavior" do
array = Spy.on []
[1, 2].each do |number|
array << number
end
array.should have_received << 1
array.should have_received << 2
end

Next Generation Testing (Testing 3.0?)
Eventually I expect all testing frameworks will follow RSpec's lead and include their own mocking support, though I'm not holding my breath since it's been two years since I originally suggested that this should happen. Today's landscape looks largely the same as it did 2 years ago. When testing frameworks take that next step, the syntax should naturally converge.

In the Ruby world you do have another option, but one with serious risk. I've been looking for ubiquitous assertion syntax for so long that I rolled my own framework in Ruby: expectations.

Expectations standardizes on both the location of your assertions (expectations) and how you express them. The following code shows how you can expect a state based result, an exception, and a behavior based result.

expect 2 do
1 + 1
end

expect NoMethodError do
[].no_method_error
end

expect Object.new.to.receive(:ping).with(:pong) do |obj|
obj.ping(:pong)
end

As a result of expectations implementation you can always look at the first line of a test and know exactly what you are testing.

Full disclosure: Before you go and install expectations and start using it for your production application, you need to know one big problem: there's no support for expectations. I'm no longer doing Ruby full-time and no one has stepped up to maintain the project. It's out there, it works, and it's all yours, but it comes with no guarantees.

In the .net and Java worlds, the future of testing looks less... evolved. In the .net world, the ever focused on testing Jim Newkirk has teamed up with Brad Wilson to create xUnit.net. xUnit.net represents evolution in the .net space, but as far as I can tell they haven't done much in the way of addressing ubiquitous assertion syntax. In Java, I don't see any movement towards addressing the issue, but can it even happen without closures (anonymous methods, delegates, whatever)?

I'm surprised that more people aren't bothered by the lack of ubiquitous assertion syntax. Perhaps we have become satisfied with disparity in syntax and the required full test scan.

Tuesday, November 18, 2008

Specialize in Something Relevant

generalist: a person competent in several different fields or activities
If you read my blog entry on Language Specialization you might have concluded that I prefer generalists. If, in our industry, generalists were what the definition describes, then I would prefer generalists. Unfortunately, business software developers seem to have created their own definition of generalist.
business software developing generalist: I know how to do the simplest tasks with many different languages/tools, but I can not be considered competent with any of them.
I blame Scott Ambler. To me anyway, it seems like the daft generalist movement started when Scott wrote Generalizing Specialists.

Our industry has always been saturated by bad programmers. I'm on record stating that at least 50% of the people writing business software should find a new profession. The problem with bad developers is that they take good ideas and turn them in to monstrosities.

I remember reading Generalizing Specialists and being inspired. I thought Scott gave fantastic and relevant advice. Unfortunately, many bad or junior developers heard: Don't bother to deeply understand anything, instead, you're agile if you know a little about everything. Suddenly, when I started interviewing developers I ran into situations like this.
  • me: So, I see you have Erlang on your resume, how do you like the language?
  • candidate: I like it's concurrency handling, but I'm a bit weary of it's syntax.
  • me: (thinking - okay, do you have any original thoughts on Erlang?) I can understand those points of view, what problem were you trying to solve with Erlang and why did you think it was the right tool?
  • candidate: Oh, I really only got through the 2 minute tutorial, you know, hello world basically. But if you guys have Erlang projects you want me to work on I'm happy to, I'm a generalist, I like all languages.
  • me: Okay, so what language would you say you know the most about?
  • candidate: I don't bother to specialize, I do a little bit with each language, you know, hello world or whatever, so I can use the right tool for the job. That's the best part of being a generalist.
  • me: (thinking - this interview is already over) Okay, so tell me about the languages/tools you've had to use at your different jobs?
Inevitably, the candidate doesn't even have a deep understanding of the tools they've used at work, because they are too busy doing hello world in every language invented. They also love to say that they take the Pragmatic Programmers advice to extreme and 'learn' several languages a year.

The truth is, these generalists have little in the way of valuable knowledge. They provide their projects with little more knowledge than a Google search can bestow in 30 minutes. In short, they're worthless, if not destructive.

I don't actually blame Scott Ambler. In my opinion he was right then, and he's right now. Become a Generalizing Specialist is still the advice that I currently give developers.

Specializing in something makes you an asset to the team. If I'm building a Web 2.0 website, I want everyone to have an understanding of HTML, CSS, Javascript, Ruby, & SQL. However, I also want each team member to specialize in one of those areas. Knowing IE quirks is just as important as knowing how to optimize MySQL. And, I want to make sure I have team members that can get into the deep, dark corners of delivering highly effective software. That doesn't mean everyone needs to know what a straight join in MySQL does, but at least 1 person should. The rest of the team isn't entirely off the hook though, they better understand how to write basic SQL statements that are maintainable and at least semi-performant.

Becoming a Generalizing Specialist takes time, but the first step is becoming a Specialist. Once you deeply understand one language/tool, you can move on to the next relevant language/tool. How do you know when it's time to move on? When you start having answers to questions that people aren't asking. If you're constantly looking up answers to common questions, you aren't a specialist. However, if you start providing more (relevant) detail in your answers than people are looking for, you're on your way to possessing the deep understanding that a Specialist should have. At that point, it's probably time to start looking deeply into something else.

One painful mistake to look out for is specializing in something less relevant. If you work for a trading firm that writes only thick client applications, understanding why Chrome's Javascript VM is better than Firefox's Javascript VM is probably not the best use of your time. It's true that you may move on to a web application at some point, but by then your information will probably have become stale anyway. Stick to specializing in things that you work with day to day. Your language, your IDE, the Domain Specific Languages you use in your applications (regular expressions, SQL, LINQ, etc), or the frameworks you use (Spring, ASP.net, etc) are things you should specialize in to increase the value you provide to your team.

Eventually, you become competent with several different tools and languages. You've become a Generalizing Specialist and as such you are significantly more valuable to your team.

Tuesday, October 21, 2008

Language Specialization

Didn't you just totally sell out? -- Obie Fernandez @ Rails Summit Latin America
Obie and I are good friends. He wasn't trying to insult me. I was talking about how much I liked my new job (at DRW Trading), and the different aspects of the job. One aspect of my job is that I spend a fair amount of my time working with Java. I do some C# and some Ruby also, but these days it's more Java than anything else. I believe Obie was genuinely curious if I felt like I sold out since I'm not doing Ruby full-time anymore.

It's an interesting question, but it comes packed with all kinds of assumptions. For the question to be valid, I would have had to trade something I truly care about for the combination of something I did and did not like. Luckily, that wasn't the case.

Obie isn't the first person to be surprised that I'm no longer working full-time with Ruby. Truthfully, I find it a bit funny that people think I would base a career move on a language. Ruby is my favorite language, but it's not the correct choice for every problem that needs to be solved. And, languages have never been my primary concern when deciding what job to take.

My first job primarily used Cold Fusion. When I joined AOL Time Warner I gave up Cold Fusion for PHP. When I joined IAG I gave up PHP for C#. And so on. As you can see, I've never been too tied to a language. I've always been most interested in learning and growing. I love jobs that help me improve my skills.

Chad Fowler talks about something similar. In the section "Don’t Put All Your Eggs in Someone Else’s Basket" of My Job Went to India, Chad says the following:
While managing an application development group, I once asked one of my employees, “What do you want to do with your career? What do you want to be?” I was terribly disppointed by his answer: “I want to be a J2EE architect.” ...

This guy wanted to build his career around a specific technology created by a specific company of which he was not an employee. What if the company goes out of business? What if it let its now-sexy technology become obsolete? Why would you want to trust a technology company with your career?
I think Chad got it right, but it's not just companies you shouldn't trust. I wouldn't base my career on any technology, whether it was produced by a company or an open source community.

I prefer jobs that allow me to learn new things. Think of it as job security -- I shouldn't ever be out-of-date when it comes to technology experience. Think of it as an investment -- everything I learn creates a broader range of experience that I can leverage for future projects or jobs. Think of it as experimenting -- by trying many different solutions I may find ways to combine them and innovate.

I've turned down several jobs that paid more or offered comfort. I've never regretted it. Your career is long and (as Chad says) you should treat it as a business. When you look at it from that perspective it obviously makes sense to spend the early years learning and deciding which is the best direction to take.

The truth is, if you focus on one technology you'll never be as good as your teammates who have more experience mixing technologies to produce the best solution.

As I told Obie, I definitely don't feel like I sold out. In fact, one of the reasons I joined DRW was because they use Java. I've never worked with Java, messaging, or the financial domain. Having experience with those 3 things will make me better. And, diversifying your experience will make you better as well.