Friday, April 24, 2009

Pragmatic (programming) language use

While doing research for an earlier post, I wondered whether the pragmatic programmers had ever come up with a definition of a "pragmatic language" in which to do one's pragmatic programming. They had not - at least none that Google was aware of.

If I'd given it any thought, I would have realized that it's not particularly pragmatic to divide programming languages into "pragmatic" and "non-pragmatic" categories. The pragmatic approach is to pick a language that's appropriate for your current project and learn to use it well, not to engage in holy wars about which languages are better than others.

Anyway, the first two hits on a Google search for "pragmatic language" led to the website of the American Speech-Language-Hearing Association, which defines pragmatics as the ability to use language appropriately in social situations. That was kind of interesting, but didn't seem germane to software development in any way - until I read this:

An individual with pragmatic problems may:

  • say inappropriate or unrelated things during conversations
  • tell stories in a disorganized way
  • have little variety in language use
Hey, pragmatics and pragmatic programming have something in common after all! Let's examine the symptoms, shall we?

Say inappropriate or unrelated things during conversations

If we substitute "programs" for "conversations", this becomes highly apropos to programming. One of the key concepts of pragmatic programming is to design components that have a single, well-defined purpose. If a component deviates from that purpose to do something unrelated, that's a code smell. Time to refactor!

Tell stories in a disorganized way

The legendary Donald Knuth introduced the concept of literate programming, which holds that it's not sufficient for a program to instruct the computer what to do; it must also explain to human beings what the computer is supposed to do. Knuth suggests that a literate programmer can be considered an essayist, and Yukihiro "Matz" Matsumoto, the inventor of Ruby, affirms this view in "Treating Code As an Essay" (Found in the excellent O'Reilly compilation"Beautiful Code".) If we agree with these wise gentlemen, then surely code must tell its "story" in an organized way to qualify as an essay.

Have little variety in language use

If a programmer employs a limited variety of coding strategies, it suggests that Maslow's hammer - "If all you've got is a hammer, everything looks like a nail" - might be to blame. This can happen when an inexperienced programmer first discovers design patterns, and becomes so enamored with a particular pattern that he or she applies it everywhere, even when it's not appropriate.

An alternative interpretation of this symptom is an unwillingness to learn or use programming languages other than the one a programmer is most familiar with - let's call this monoglot programming, to contrast it with the increasingly popular practice of polyglot programming.

I'm not suggesting that pragmatics and pragmatic programming have any deeper connection than this. Language pragmatics are innate, whereas pragmatic programming must be learned. I'm certainly not implying that a deficit of pragmatic programming skills indicates a possible brain injury! But it's interesting to see how easily deficiencies in the domain of language development can be recast in terms of software development, despite being linked only by a coincidental overlap in terminology.

Tuesday, April 21, 2009

Clean Scala?

In recent posts, I've reviewed "Programming in Scala" and "Clean Code". These two books have very different goals, but reading them concurrently got me thinking about how the relationship between a programming language and its users (i.e. software developers) changes over time, and the implications that has on code quality.

Programming in Scala and Clean Code are both products of their respective languages' life cycle. After several years in incubation, Scala is just starting to make its way into production applications and generate some buzz. Right now, experienced Scala developers are probably outnumbered by curious newbies by a factor of ten or more. The timing of "Programming in Scala" could not be better - an excellent introductory book is exactly what the nascent Scala community needs to bring more developers into the fold.

In contrast, there's absolutely no need for another introductory Java book. Since the mid-90's, literally dozens have been published, and some are now in their seventh or eighth edition. There's no shortage of Java developers, just a shortage of developers who can code Java well. Hence the need for books like "Clean Code", which advise developers on how to deal with poorly-written Java code, and discourage them from writing any bad code of their own.

Reading these two books concurrently had me wondering if some years' hence, there will be a need for a "Clean Scala" book. I certainly hope not. The creators of Scala took advantage of many "lessons learned" from Java (and other languages, presumably) to craft a better language. One of their goals was to allow developers to write concise code that more clearly expresses their intentions. I think Scala has achieved that goal, but making expressive code easy is not the same thing as making it mandatory.

The elegant code examples in "Programming in Scala" make it hard to imagine that anyone could ever write crufty code in Scala. However, I've learned - the hard way - not to underestimate a developer's ability to warp and misuse a language in ways its creators could have never imagined.

At this early stage, it's not clear to me what the most notorious abuses of Scala will be, nor how much frustration they will cause the developers who have to clean up the mess. Will future Scala masters still exhort novices to use expressive variable and function names, to avoid repeating themselves, to follow the Law of Demeter? Will the beauty of Scala make these truths self-evident? Or will Scala introduce its own unique set of anti-patterns? My hopes are for the best, but I guess we won't know for a few years.

Sunday, April 19, 2009

Review: Clean Code

"Clean Code"by Robert C. Martin is not a conventional programming book. It's not about a new language, framework, methodology or tool. It's about how to be a better developer.

As such, it has much in common with books likeCode Complete,Effective Java,The Pragmatic Programmer,Refactoring, andImplementation Patterns, all of which fall into a genre I've dubbed "self-help books for software developers". I'm not being dismissive here: after all, systems can be just as dysfunctional as families. As developers, we can benefit from some good advice on how to cope.

Much of the advice that "Uncle Bob" dispenses will be familiar to readers of those other books. (Indeed, "Clean Code" references "Refactoring", "Implementation Patterns" and "The Pragmatic Programmer" quite extensively.) I find this redundancy comforting rather than disappointing. After all, if all these books disagreed about what the best software development practices were, how would you know which advice to follow?

(However, there is a certain irony in having read about the DRY principle - "Don't Repeat Yourself" - in three different books.)

Despite the commonalities with its predecessors, "Clean Code" is more than just a rehashing of old advice. The unique aspect of "Clean Code" is the section near the end of the book where "Uncle Bob" uses the principles laid out in the preceding 12 chapters to refactor samples real-world code drawn from the JUnit testing framework, the JCommon library, and his own work.

It was fascinating to see perfectly functional code iteratively refactored into "clean code" much better suited for reuse and further extension. Other books have explained this principle and demonstrated it on small pieces of example code, but only in "Clean Code" have I seen it applied to widely-used open-source code.

If you've ever wanted to refactor some dysfunctional code but not known where to start, or doubted that the end result would justify the effort, you should read Martin's book; it will give you the hope and confidence to give it a try.

Review: Programming in Scala

I first heard about Scala from Elmi, a co-worker of mine who was messing around with functional programming languages in his spare time. His obsession with lambdas and monads seemed peculiar at first, but when pressed for an explanation, he made a persuasive case for Scala, so I decided to check it out.

The documentation at the Scala website certainly sparked my curiosity. After learning about Scala's innovative features and reading some impressively concise Scala code, I understood why developers like Elmi were so excited about it. However, even after reading the free documentation, I felt like I was still missing something, so I caved in and bought a copy of"Programming in Scala" by Martin Odersky, Lex Spoon, and Bill Venners.

Typically, the first book written about a language isn't necessarily the best book about that language, but Odersky, Spoon and Venners have set the bar fairly high for authors of subsequent books about Scala. Higher-order functions, closures and partially-applied functions are probably going to seem quite alien to most developers unfamiliar with functional programming, so the authors are to be commended for explaining those concepts so well. Likewise, Scala's case classes, type inference system, and implicit conversions also get excellent treatment. "Programming in Scala" filled in the gaps in my understanding of Scala with remarkable thoroughness.

(Ironically, I suspect that the excellence of "Programming In Scala" is only partly responsible for the Jolt Productivity Award it recently won; an equal share of the credit - if not more - should to the Scala language itself. My hypothesis is that the Jolt Award voters, deprived a "Best Language" category in which to register their enthusiasm for Scala, rewarded the only published Scala book instead. Fortunately, since the creator of the language is one of the book's authors, there's no controversy here.)

I wholeheartedly recommend "Programming in Scala" to any developer currently working with Java. I'm convinced that Scala is destined to become an "everyday" language on the JVM, and knowledge of Scala will be essential for any well-rounded Java developer. Even if I'm wrong, and you never get to write a line of production Scala code, this book will improve your understanding of Java by demonstrating an alternative approach to inheritance, abstraction and typing in the JVM.

Wednesday, April 8, 2009

Enabling Java 1.6 for Mac OS X

OK, I might be the last Java developer using a Mac to realize this, but apparently Mac OS X 1.5 (Tiger) uses J2SE 5.0 by default, even though Java SE 6 has been available for nearly two years.

I figured this out today while reading Google's instructions on how to create Java applications for App Engine. (Side note: Woot!) The section regarding compatibility with different versions of Java contained this curious sentence:
For developers that don't have easy access to Java 6 (such as developers using Mac OS X), the App Engine SDK is compatible with Java 5.
That was a head-scratcher. I know that Apple's support for Java usually lags Sun's releases for Windows/Solaris/Linux by a few months, but Java 6 was released over two years ago. Surely Apple has caught up by now, right? To the Terminal window!
Hank:~ mtye$ java -version
java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing)

Huh. That can't be right, can it? No, a little poking around on Apple's site reveals that Java SE 6 was pushed out to users with Java for Mac OS X 10.5 Update 1, back in May 2008. So where's my Java 6?

I found a crucial clue here. Apparently, in the /Applications/Utilities/Java directory, there's a Java Preferences application that can be used to determine which Java version is used by default. I fired it up and got this:

Oh, there's Java 6! Right behind the 32-bit version of Java 5, for some reason. Let's fix that with a little drag & drop:


Let's check again:
Hank:~ mtye$ java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06-153)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_07-b06-57, mixed mode)
Ah, that's much better. I feel so 2007 now!

Thursday, April 2, 2009

Running Grails unit tests in Intellij IDEA

In my previous post, I suggested that I'd have some useful ideas to share with you. In this post, I hope to deliver on that promise by explaining the frustrations I encountered while unit testing a Grails project with IntelliJ IDEA, and the workaround I came up with to ease my pain.

First, some background. I like Grails - a lot. It dispenses with a lot of the gunk that makes developing web apps in Java so tedious: XML configuration files, repetitive boilerplate code, tag library descriptors. Grails utilizes proven technologies like Spring, Hibernate, and SiteMesh for its core functionality rather than re-inventing the wheel. And it stole, um, borrowed, lots of great ideas from Ruby on Rails, including the use of a dynamic language, i.e. Groovy, to underpin the whole framework.

Grails also has the best testing support of any framework I've used: automatic generation of test classes, an integrated test environment with an in-memory database, and with version 1.1, comprehensive mocking support for unit testing. The Grails team seems determined to eliminate every conceivable hindrance to testing, and that's an admirable goal.

However, I don't love absolutely everything about Grails testing. In particular, Grails' mechanism for running unit tests is painfully slow. The Grails test-app command runs both unit and integration tests by default, but with the -unit parameter, it runs just the unit tests and doesn't bootstrap an integration test environment. This speeds up the test cycle considerably, but it's still pretty slow; on my machine it takes Grails 10 seconds to run the unit tests - even for a project with no tests!

Ten seconds may not seem like a lot of time, but if you're trying to practice a "test a little, code a little" style of TDD, it's like sand in the gears. When I'm working with unfamiliar code or attempting a tricky refactoring, I like to run the unit tests after every change that could conceivably work. That way, if the tests fail, I can undo my change without having wasted much time or effort.

However, when it takes 10 seconds to run a unit test, there's a temptation to skip the tests, stay in the flow, and keep coding. When I finally run the tests, there's always a failure of some kind, and fixing it usually necessitates a substantial reworking of the code. The longer it's been since I ran the tests, the more rework is required.

After getting bit by this a few times, I started looking for a better way to run Grails unit tests. My first instinct was to run the tests from within my IDE: there's nothing more convenient than firing off your tests with a keyboard shortcut. Unfortunately, I discovered that IntelliJ's "Grails Tests" run configuration just delegates to Grails' test-app script. While running the unit tests from within IntelliJ was a improvement, it wasn't any faster than using the command line.


Since Grails tests inherit from junit.framework.TestCase, my next tactic was to run the tests with IntelliJ's JUnit test runner:


This was a considerable improvement. The tests ran significantly faster - two or three seconds instead of ten - and the results appeared in IntelliJ's Run window, with a summary of failed tests and clickable links in the stack traces. Very nice!


There was one problem, though. As you can see from the above screenshot of the JUnit run configuration, IntelliJ has three options for selecting which tests to run: a single test method, a single test class, or all tests in a package. None of these options works very well for unit testing Grails projects. A single class was too limiting, since I didn't want to maintain a test suite with a reference to each unit test class. Conversely, the "all tests in a package" option was too permissive: it would run both the unit and integration tests, and without a Grails test environment, most of the integration tests would fail.

I wanted an option that would run just the tests in the test/unit directory, but IntelliJ's built-in test runner couldn't be configured to do that. After much fruitless searching, I finally found the solution on the Groovy website. Groovy has a utility class named AllTestSuite that finds all the tests that match a filename pattern in a given directory and aggregates them in a test suite. Normally, AllTestSuite gets the base directory and the filename pattern from the system properties, but it's easy enough to extend the class and specify the directory and pattern with static variables, like so:

import junit.framework.Test

public class AllUnitTestSuite extends AllTestSuite {

private static final String BASEDIR = "./test/unit"
private static final String PATTERN = "**/*Tests.groovy"

public static Test suite() {
return suite(BASEDIR, PATTERN)
}

}

I put the above code in a file named AllUnitTestSuite.groovy in the project's test/unit directory, ran it with IntelliJ's JUnit test runner, and it worked perfectly. Fast, convenient, and exactly what I want: problem solved!



A nice bonus here is that under the covers, AllTestSuite uses a Gant script to collect the tests, so if you're familiar with Ant FileSets, you can tweak the matching pattern to customize your test suites.

Thursday, March 26, 2009

Why "Code Shark"?

Well, it's certainly not because I think of myself as a relentless apex predator, prowling the seas of software development. Rather, I'm alluding to the fact that certain species of shark (specifically, obligate ram ventilators) have to keep swimming in order to survive. Lacking the ability to breathe in the conventional piscine manner, these sharks maintain a steady flow of oxygenated water over their gills by swimming forward with their mouths open. If they were ever to stop, they would suffocate and eventually die.

I've been coding for a living for almost two decades, and in that time, I've learned that a career in software development has something in common with those sharks: if forward motion stops, it suffocates and dies. "Forward motion", in this case, means the acquisition of new skills: new languages, new tools, new methodologies, and even new ways of thinking.

If you keep up to date, a wider variety of interesting projects are available to you. If you fall behind, you get stuck maintaining crufty legacy code. (Or worse, you get a Dilbert Principle promotion and become one of those managers who has no clue what his/her underlings actually do.)

Many years ago, I had a career near-death experience: I unwittingly drifted into a dead-end job maintaining an obsolete system. When I decided it was time to move on, I was stymied because I possessed none of the skills my employer required for new development projects. Looking for jobs at other companies was equally fruitless; the only opportunities open to me involved maintaining the same kind of obsolete system!

Escaping from this trap required a complete career reboot: I quit my job, learned a new language and paradigm (Java and OOP), and persevered until I found an employer who was more concerned with my potential than my experience (or lack thereof). I was relieved to get my career moving forward again, but it was very costly in both time and money - it would have been far better to never get stuck in the first place.

In the years since, I have made a concerted effort to fill in the gaps in my skill set, so as never to become obsolete again. It's a daunting challenge; the software development ocean is so vast that keeping up to date is nearly a full-time job in itself. So far, the investment has paid off: each of my jobs has been more rewarding - intellectually and financially - than the last.

In this ongoing process of reading, learning, and acquiring new software development skills, I've occasionally made discoveries that might be helpful to others who are on a similar journey. I've belatedly set up this blog to share these ideas with a wider audience. I hope you find them useful, or at least entertaining.

Keep swimming!