the blog for developers

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

You can leave a Reply here. Of course, you should follow me on twitter here.

You can share this post!
Do you want to tell others about this article? Use the social bookmark icons to submit this artice to the service of your choice. Thanks.

About the author: Stephan Schmidt has more than 15 years of internet technology experience and 10 years experience in agile. He was head of development, consultant and CTO and is a speaker, author and blog writer. He specializes in organizing and optimizing software development helping companies by increasing productivity with lean software development and agile methodologies. Want to know more? All views are only his own.
Leave a reply.

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”).

[...] Code Monkeyism: Ruby: Complexity cannot be reduced @dnene Ah here: http://bit.ly/9pyU6I "Ruby: Complexity cannot be reduced" #ruby – Stephan Schmidt (codemonkeyism) http://twitter.com/codemonkeyism/statuses/22063730581 (tags: from:codemonkeyism ruby via:packrati.us) [...]

Leave a Reply

What people wrote somewhere else:

Additional comments powered by BackType

Guide to CodeMonkeyism

Over the last 4 years I wrote many articles on this blog. To make it easier for you to find the relevant ones, I've organized them into topics.

Top 10

6 reasons why my VC funded startup did fail

Go Ahead: Next Generation Java Programming Style

Java Interview questions: Write a String Reverser

The dark side of NoSQL

7 Bad Signs not to Work for a Software Company or Startup

Is Java dead?

Scala vs. Clojure

Never, never, never use String in Java

No future for functional programming in 2008 – Scala, F# and Nu

Clojure vs Scala, Part 2

Java Developer

Is Java Dead?

Go Ahead: Next Generation Java Programming Style

Be careful with magical code

All variables in Java must be final

Never, never, never use String in Java

Bending Java: More readable code with methods that do nothing?

NoSQL Guy

NoSQL: The Dawn of Polyglot Persistence

The dark side of NoSQL

Essential storage tradeoff: Simple Reads vs. Simple Writes

Sharding destroys the goals of your relational database

The unholy legacy of databases

Startup/CTO

Development Dream Teams

6 reasons why my VC funded startup did fail

American vs. European style of Software Development

12 Things to Reduce Your Lead Time and Time to Market

The high cost of overhead when working in parallel

Essential storage tradeoff: Simple Reads vs. Simple Writes

Job Seeker

Another Good (Java) Interview Question

7 Bad Signs not to Work for a Software Company or Startup

Java Interview questions: Write a String Reverser (and use Recursion!)

Java Interview questions: Multiple Inheritance

As a Manager: What I value in developers

Top 10 Tips (+1) to Get a Pay Raise

Agilist

What Developers Need to Know About Agile

5 Practices Better to Change in Your Scrum Implementation

Scrum is not about engineering practices

ScrumMaster and ZenMaster: The joke of certification

What is Trans-Scrum?