Code Monkeyism

Programming is hard by Stephan Schmidt

Ruby: Complexity cannot be reduced

There is a lot of discussion about concise code. Comparing Java to Ruby, obviously Ruby has more concise code (This article contains code examples, which could be written better and which experienced Java and Ruby developers would write in differently. But the examples were chosen to illustrate points).

Compare this Ruby code taken from the Pragmatic book

songType = if song.mp3Type == MP3::Jazz
            if song.written < Date.new(1935, 1, 1)
              Song::TradJazz
            else
              Song::Jazz
            end
          else
            Song::Other
          end

with the corresponding Java code:

public SongType getType(Song song)  {
       if (song.isMp3Type(Mp3Jazz.class) {
               if (song.isWrittenBefore(new Date(1,1,1935)) {
                       return SongType.TRAD_JAZZ;
               } else {
                       return SongType.JAZZ
               }
       } else {
               return SongType.OTHER;
       }
}

Java has more code than Ruby in this example, but the cyclomatic complexity is the same for both examples. Although the size of the Ruby example could be reduced, in this version the LOC is also the same. You can’t reduce the CC with choosing another language, only by choosing another algorithm or language paradigm.

When adding comments to the code examples like this

/**
 * Gets the song type from a song. This does not
 * return the mp3 type information from the song
 * but tries to determine the song type from the mp3 type,
 * time period and other enviroment variables
 *
 * @param song the song which should be checked
 * @return the song type for the song
 */
public SongType getType(Song song);

or like this for a dynamic-reference-typed language:

/**
 * Gets the song type from a song. This does not
 * return the mp3 type information from the song
 * but tries to determine the song type from the mp3 type,
 * time period and other enviroment variables
 *
 * @param {Song} song the song which should be checked
 * @return {SongType} the song type for the song
 */
 def type(song) ...

The difference between the two language styles dimish and the CC [1] to understand the code for a developer which has never seen the method is the same. In his head he has to order and solve the nested if statements to come to an understanding of what the method does. He might parse the Ruby example faster, because it’s more concise, but the understanding part after the mental parsing is the same. Current studies show though that people don’t read and parse text word by word but detect meaning by looking at patterns of word beginnings and endings. This would suggest that less code doesn’t increase parsing speed a lot.

If conciseness of code is the deciding factor for faster understanding written code, then languages like K should be instant (some K programmers claim to instantly understand code by seeing it). A Hilbert matrix [2] in K [3] looks like this:

 {1%(!x)+\:1+!y}

The Java example from before can be written more understandable, for example with the Hamcrest library. This code is even less concise, but easier to understand

public SongType getSongType(Song song)  {
       if (is(song.getMp3Type, equalTo(Mp3Jazz.class)) {
               if (is(song.written(), before(1,1,1935)) {
                  return SongType.TRAD_JAZZ;
               } else {
                  return SongType.JAZZ
               }
       } else {
               return SongType.OTHER;
       }
}

It would be very interesting to see studies which compare code styles, conciseness and cyclomatic complexity and how they releate tounderstanding code which you haven’t written. Because as Robert Glass writes in the excellent facts and fallacies of software engineering: “Fact: Maintenance is the most important life cycle phase with 40-80% of the cost.” I have currently the feeling that most language innovation happens with rapid development, not low maintainance.

[1] http://www.fromthetrench.com/category/cyclomatic-complexity/
[2] http://en.wikipedia.org/wiki/Hilbert_matrix
[3] http://www.langreiter.com/space/k-notes

About the author: Stephan Schmidt is currently a team manager at ImmobilienScout24 in Berlin. Stephan has been working as a head of development and CTO. He has used a lot of different technologies in the last 20 years including Java, Rails and Python. Stephans main field of interest is maintainablity and productivity in software development. Want to know more? All views are only his own.

If you did like this article but you don't want to subscribe to new articles with your reader, you can follow me on Twitter or subscribe to new posts with your email:

Comments

afsina

Some thoughts on your java code:

- new Date(1,1,1935) is deprecated. you can use GregorianCalendar instead. Java 7 will have better datetime handlin tough.

- you can use static import for SongType in Java code, it would reduce the code crowd. as: SongType.TRAD_JAZZ -> TRAD_JAZZ

Lastly,

if (song.isMp3Type(Mp3Jazz.class) sounds a little awkward to me. it smells a little but cannot say much before i see the full code.

stephan

Hi afsina, thanks for your comment.

Some thoughts on your comment:

- I usually use JODA or a Calendar (if I have to)

- I wanted to stay close to the Ruby example, as the preface states: “This article contains code examples, which could be written better and which experienced Java and Ruby developers would write differently.”

- As said there is no full code. These were some code example to illustrate the CC points made in the post (”But the examples were chosen to illustrate points”).

Leave a Reply