Wednesday, August 30, 2006

Ruby Quiz #6: Too Simple?

Matt Secoske and I were pairing last night and we decided to work on quiz #6 from the Ruby Quiz book. Here's our code complete with tests.
require 'test/unit'
require 'test/unit/ui/console/testrunner'

module Enumerable
def in?(candidate)
any? {|any| any.in? candidate}
end
end


class Fixnum
def in?(candidate)
equal? candidate
end
end


class Range
def in?(candidate)
include? candidate
end
end


class BuildRegexp
GUARD = /^[0123456789]+$/

def initialize(candidates)
@candidates = candidates
end

def =~(candidate)
GUARD =~ candidate && (@candidates.in? candidate.to_i)
end
end

class Regexp
def self.build(*candidates)
BuildRegexp.new(candidates)
end

end


class BuildTest < Test::Unit::TestCase
def test_lucky()
lucky = Regexp.build(3,7)
assert('7' =~ lucky)
assert(!('13' =~ lucky))
assert('3' =~ lucky)
end

def test_month()
month = Regexp.build(1..12)
assert(!('0' =~ month))
assert('1' =~ month)
assert('12' =~ month)
end

def test_day()
day = Regexp.build(1..31)
assert('6' =~ day)
assert('16' =~ day)
assert(!('Tues' =~ day))
end

def test_year()
year = Regexp.build(98,99,2000..2005)
assert(!('04' =~ year))
assert('2004' =~ year)
assert('98' =~ year)
end

def test_num()
num = Regexp.build(0..1_000_000)
assert(!('-1' =~ num))
end

end

Test::Unit::UI::Console::TestRunner.new(BuildTest.suite()).start()

Of course, we excitedly looked up the answer in the book and were shocked. Their final answer was longer and harder to understand. Our code uses less of the regular expression class. In fact, we only used it as a guard to make sure we could convert the input to a number. We also made heavy use of polymorphism and duck typing(in?, =~). As you can see the code is very short.

The quiz was to build a Regexp to handle any list or range of numbers. The tests are taken exactly from the book and of course, we wrote them first. Well, actually, we wrote them at each stage. At one point, we were using Regexp extensively until we hit the last test. And that is when the change in requirements caused all of the code you see above.

How fun! We looked at each other and wondered, "Was our solution too simple?" We then laughed and said, "Nah." We were both proud for our simple and readable solution.

Tuesday, August 29, 2006

What Do You Value?

I keep coming back to a study that Steve McConnell mentions in Code Complete 2. The study was conducted by Gerald Weinberg and Edward Schulman to study the setting of quality objectives. The table below taken from the book always shocks me.







Objective To MaximizeMinimize MemoryMost Readable OutputMost Readable CodeLeast CodeMinimize Programming Time
Minimum Memory14425
Output Readability51153
Program Readability32234
Least Code25313
Minimum Programming Time43541

Basically, it shows we achieve what we value. But, it also shows that the worst performer on the other metrics was "Minimize Programming Time" and the best overall is "Most Readable Code". I think we should always strive for readable code, but this study shows that the side effects are nice too.

I think sometimes XP shops can get too caught up in miniminizing programming time and thus, lose sight of the quality we should value most. We just need to be mindful and keep our code readable!

Behaving Poorly At Work

If you feel bad at work, go home. Feeling bad is no excuse to behave poorly. It's unprofessional and juvenile at best. OK, I'll get off my soap box now.

Monday, August 28, 2006

Matt's Ruby Log Splitter

Matt Secoske posted a Log Splitter on his blog. I thought it was a fun exercise, so I wrote my own as well. My version is different in that I made the work of splitting files into a class of its own that understands the same protocol of IO stream (or the parts that I need right now). All you do is simply create it like any another File object, except add a block that evaluates when the file should be split into a new one. The code at the bottom uses it. I tried to keep close to the input parameters of Matt's original code. Later on, I inspired him and he came up with a DSL version. Remember, I whipped this code up pretty quickly and I was having a bit of fun with Ruby. Enjoy!
class SplitFile
def self.open(suffix, mode, &when_to_split)
self.new(suffix, mode, when_to_split)
end

def write_all(enumerable)
enumerable.each {|line| write(line) }
end

def write(line)
open_next() if should_split?(line) || @file.nil?
@file.write(line)
end

def close()
@file.close() unless @file.nil?
@file = nil
end

private
def initialize(suffix, mode, when_to_split)
@suffix = suffix
@mode = mode
@when_to_split = when_to_split
@file_count = -1
end

def open_next()
close()
file_name = next_file_name()
puts "Writing file #{file_name}"
@file = File.open(file_name, @mode)
end

def next_file_name()
@file_count += 1
"#{@file_count}_#{@suffix}"
end

def should_split?(line)
@when_to_split.call(line)
end
end


FILE_SUFFIX = ARGV[0] ? ARGV[0] : "split.log"
MAX_LINES = ARGV[1] ? ARGV[1].to_i : 500000

lines = 0
split=SplitFile.open(FILE_SUFFIX, 'w') do |line|
lines += 1
result = lines >= MAX_LINES
lines = 0 if result
result
end

begin
split.write_all($stdin)
ensure
split.close
end

Sunday, August 27, 2006

Python and XML in Omaha

It's time for another bodacious meeting of the Omaha Dynamic Language Group! This month we have a great presentation by Mike Hostetler on "Python and XML". Mike has a lot of passion for Python and he wants to show off one of the strong points of Python: XML. He will be taking us on a journey into the Python libraries. It should be a trip of elegance and simplicity. Come join us September 5 @ 7pm.

We do have a new location this month. Here's the details:
Creighton University
2500 California Plaza
Omaha, NE 68178

Parking
Additional Information:
Enter the west end of the Old Gym.

Go up the elevator to the fourth floor.
You're there.
Restrooms are on the 2nd floor, unfortunately.
Vending machines are on the 1st floor, around the wall to the right of the elevator.
Anyone asks, you are attending the Omaha Dynamic Users Group meeting on the fourth floor of the Old Gym or ODUG.

Think Good Thoughts

Saw this on a t-shirt:
Think Good Thoughts.
Words become actions,
Actions become habits,
Habits become character,
Character becomes destiny.

I love it!

Wednesday, August 23, 2006

Oh No! Let's Not Hurt Our Brains!

I couldn't believe this when I read it. It's an article arguing against closures in Java because they might be hard for some developers. I guess we should have never moved beyond ones and zeros either. Paradigm shifts always require us to look at things differently. I know I looked at the world differently after I learned Smalltalk or Lisp or Erlang or Haskell. Each of these languages pushed me into unfamiliar territory. Sure, it all looked alien and weird when I started with each one, but I soon learned.

To not do something because you are afraid of the average programmer is ludicrious. They never will become more than average if we don't push them. I'm sure object-oriented programming was scary at first for a lot of developers, but they learned. To not do a feature because it might confuse the "not-so-bright" developers is assuming too much. I'm reminded of a quote by Paul Graham:
"If you think you're designing something for idiots, odds are you're not designing something good, even for idiots."

If you don't know the power of closures, please go read "Structure and Interpretation of Computer Programs" right now! Don't worry...It's not only for smart people.

Saturday, August 19, 2006

Pepsi through the nose hurts...

Need a good laugh? Read "How To Write Unmaintainable Code" right now! I've ran into a lot of the code he talks about and it's not only hard to maintain, but hard to refactor as well! An excellent anti-essay that will make you laugh, but also teach you what to avoid. Feel sorry for those that have to clean your mess at 3am in the morning.

Goodbye, Smalltalk

I'm having to say good-bye one more time to my favorite language. Oh, don't worry, I'm not leaving the community. I just will not be doing Smalltalk full-time at my job. I haven't been doing it for awhile anyway, but I occassionally walked over to the Smalltalk side of my shop and helped out on hard problems. my new gig will be 100% Java.

I'm looking to the future with excitement. RubyConf is going to be interesting to see how their community works. My experiences with the Ruby community have been positive, but it's been by all email. It will be cool to meet a lot of people in person. Of course, it will be cool to give a demo of Squeak or Dolphin to anyone that wants one.

The sad new is that I will probably not attend any of the Smalltalk conferences any time in the near future. Everyone will be missed! But, I will be out there trying to show Smalltalk to anyone curious (at RubyConf and beyond).

I will always love Smalltalk...

Generics not so bad

I've been working Java 5 the past 6 months and while there's a lot about generics that make me cringe, they are not that bad. "What?!", you exclaim. The 433 pages of FAQ outlining all of the fringe cases and the single variable names do make me want to pull my hair out. But, the 433 pages outline mostly things that you should never do anyway. I have found that generics make bad design and poor programming harder. This is a good thing. Generics become painful when you try to have lists of lists of lists of lists. It forces you though pain to refactor to objects.

I've also noticed that Hibernate forces you in the same ways. Everytime I do something complicated in Hibernate, I have found it's a pain. And everytime there was an easier and more elegant approach that would not only appease Hibernate, but make my design better.

Funk Card Ready, Mothership Taking Off

It's official. I resigned from my current position this week. I will be joining Union Pacific to do J2EE and some Jess. I'm excited about the team that I'm going to be a part of. I love playing with rules engines and this position is working closely with clients. Union Pacific is trying to solve some wicked hard problems and I think my brain is going to be stretched. Should be mad fun! I hope the team knows what they have gotten themselves into...=)

Sunday, August 13, 2006

Amen Brother!

Small Teams Make Better Software is simply a great blog post. It hits the nail right on the head. I'm a firm believer in agile processes, but I'm becoming less and less enamored with XP. Anyway, it's a great article that is glowing about agile with the caveat that you must know the context to use it. Excellent stuff!

Diet Pepsi Jazz: Strawberries & Cream

The best soft drink ever made. I'm so much in love. It makes any bad day feel good. I wonder if they would let me be their spokesmodel....=)

Saturday, August 12, 2006

Gross Code

Mike Bowler finds some gross code. Unfortunately, there's tons of examples in the JDK. My favorite has to be the Collections class in java.util. Why you ask? For example, the method sort(List) really should have been on the List interface. I also don't like the fact that it modifies the List and doesn't return a copy. I'm of the opinion that utility classes are usually a warning sign of lazy design. I understand that you do need them, but I try to hide their usage behind my objects. I never expose them.

Jerry Goldsmith

I just read that Jerry Goldsmith died of cancer at age 75 recently. Wow. As far as movie soundtracks, he's one of my favorites. He gave the world creepy music in "The Omen", futuristic pomp in "Logan's Run", tribal dissonance in "Planet of the Apes", and so much more. His music was inventive and fit the scenes perfectly. His music and legacy will live on in my heart.

Critical Communities

I was reading a blog entry on the Java and Ruby communities. It was interesting in the fact that the chose the Java community because of "critical" participants like the Bile Blog. It was argued that the Ruby community is too over-zealous and not critically introspective.

Well, I'd like to be brutally honest right now. Cursing and calling people "stupid" does not make a community. It discourages existing members and pushes potential new members away. I think being introspective and honest in your community is a must. I see this in spades in both the Ruby and Java communities. If you look long enough at the Ruby blogs, you will notice that we are all aware of the problems. Same goes for the Java community as well. But, what makes me love the Ruby community is the "roll up your sleeves and help" mentality. If you don't like something, work to make it better. I find this extremely positive. Now, I know this is in the Java community as well, but it's more pronounced in the Ruby community.

I find that the Bile Blog gives the Java community a black eye and it's one of the reasons why people are flocking to the Ruby community. It's more positive and not yet mired in endless negativity. I would be shocked if there was ever a Bile Blog for Ruby.

I like being apart of both communities. They both have things I love. But, I love the overwhelming positivity of Ruby. I think a lot of that comes from Matz.

Sunday, August 06, 2006

Interesting Quote

"I always knew one day Smalltalk would replace Java. I just didn’t know it would be called Ruby."
-- Kent Beck

I got it from ozmmdotorg blog.

Shallow Knowledge

I'm rediscovering my "AI self" this week and came across this:
IF a person has a pink monkey
THEN take a refrigerator

It comes from the excellent book, "Expert Systems: Principles and Programming" by Giarratano and Riley. They use it as an example to make their point about shallow knowledge structure. It made me laugh because it's so silly, yet made their point perfectly clear. I love the book and it's one where you can pick it up and start reading at any point. A great book to read if you're interested in expert rule systems. Plus, they have funny examples that make you think.

Sepultura and Talladega Nights

We saw "Talladega Nights" on Friday and it was a hoot. But, I shocked in one of the final scenes when they used music from Sepultura's "Arise" album. I couldn't believe it. I'm an old school thrasher and underground metal lover. Back in the day, it would have been unheard of to hear something like Slayer or Metallica in a movie, yet alone Sepultura. It put a big smile on my face. I'm wondering if Will Farrell is a metal fan ("Master of Puppets" is played in a scene in another of his movies). Pretty cool to hear some of the music that I moshed to when I was young. Funny thing is that music still sounds great after all of these years.

Saturday, August 05, 2006

My Wife: The quick pick me upper

Last week was a devestating for me personally. I put a lot of energy into something that just wasn't meant to be. It was one of those "if it doensn't kill you, it will make you stronger" moments. I've been hurting all week and my wife knew it. I didn't talk about it much, but I was distant.

So, what does she do? She gave me an empty journal with a mocked up cover of the book I want to write eventually. She knows my ambitions and the cover was gorgeous. It had a lot of funny quotes from various people about my book (of course, they were fake). But, it's exactly what I needed to lift my spirits.

She always knows exactly what to say to me to cheer me up. This gift touched me beyond words. It is the journal I will keep for my ideas on "Balance". She is the person that picks me up when I fall and tells me to push forward. This week has been a failure week and my new journal will be where I write my new successes.

I love my wife. She is the best. I wish everyone had a Michelle in their lives.

I'm reminded of two quotes that keep me going:
"Winners are losers who got up and gave it one more try."-Dennis DeYoung
"Good thoughts bear good fruit. Bullshit thoughts rot your meat."-George Clinton

More About Examples

I've been meaning to post some comments Joe left me:
Blaine,

I don't read your blog as often as I'd like, but whenever I do it gets me thinking.

I cut my teeth on the first edition of "Java in a Nutshell" and agree many of the code examples are horrible. For some unfathomable reason, most Java books make little or no attempt to teach OO concepts, choosing instead to focus on syntax and the API.

The problem with correcting code is that your corrections are open for correction :) In fixing the "baby sins" you've created, IMHO, a more egregious one. public methods with filname parameters is generally a Bad Idea as it allows a careless coder to corrupt any file of his choosing.

Well, but, I was trying to show a simple example. Wait a minute. I'm in the very quicksand that I complained about. Ouch. You are so right. I would generally have file access behind some kind of broker and then had the operations split out. Darn it! Maybe I should keep my mouth shut because it's hard to come up with succint yet correct examples.
You've also created some minor baby sins (embryo sins?) yourself. I believe redundancy does not necessarily lead to clarity. The repetitive "InCents" while well intended, gets downright annoying. I only need to be told once that we're dealing in cents. When you switch to another unit measure, let me know, otherwise it should be safe to assume nothing has changed. Make cents, er, sense? By renaming the method to addCentsToPurse, it pretty clear that cents is the order of the day.

Well, I usually have an object to represent money. Wait a minute. I'm down my rat hole again. DARN IT! You are exactly right. The "InCents" does get annoying. I usually put them in when I'm dealing with legacy code that deals in primitive. I don't like dealing with primitive types at all. Again, it's hard to come up with good examples. I should have done the right thing. I wrote the counter example in haste and committed sins in my rush.
Your constant and variable names are a little too "techie." I've lately come to understand that if code can be read by a non-coder, coders will be able to read it all the faster. seek(TOTAL_AMOUNT) is less technically accurate than seek(RECORD_POSITION) but it more clearly indicates what we expect to find at that location.

Another great suggestion and one that I fight with constantly. I do try to come up with good variable names, but I do fall into the techie trap a lot. Thank you for giving me more ammo to fight this battle in my head.
So, here's my version (hoping the format looks ok):

private static final String PURSE = "blah";
private static final String READ_AND_WRITE = "rw";
private static final int TOTAL_AMOUNT = 100;

public void addCentsToPurse(int cents) throws IOException {
RandomAccessFile purse = new RandomAccessFile(PURSE, READ_AND_WRITE);
try {
purse.seek(TOTAL_AMOUNT);
int centsInPurse = purse.readInt();
int total = centsInPurse + cents;
purse.seek(TOTAL_AMOUNT);
purse.writeInt(total);
} finally {
purse.close();
}
}

As a final note, I'm always tempted to combine multiple lines, as in:

purse.writeInt(centsInPurse + cents);

While this is a trivial example, it does help with debugging to use a new variable and multiple lines.

Jeff

WOW. Excellent code. I love these kinds of comments. It should a lot of faults in my code and I learned a lot. Great stuff. And we got a better example out of it to boot. Thanks, Jeff...You ROCK! I will work harder to make my code the best it can be and encourage everyone else to do the same thing.

My Boys!

Go check out Hematovore right now. These are the guys that I hung out with in college. Ah, the memories and this is their band. This stuff seriously rocks. You must go now if you like good rock music! They have a new CD out and I'm so proud of them.

Friday, August 04, 2006

Running

I took up running in the morning last winter and got hooked. I stopped in March because of allergies and a busy schedule. I just recently started again and I immediately noticed this time how much better I felt during the day. My attitude is more positive and I can think more clear. If I don't have my morning run, I can tell a huge difference. I think at this point, I will not quit again. It just feels too good. Plus, the amount of ideas that I'm having is incredible. I feel in charge and ready to take on the world. Why didn't I notice this difference the first time I quit? It's like night and day. Here's to feeling great and running!

Wednesday, August 02, 2006

Lisp In Omaha

Sam Tesla gave the whirlwind presentation on Lisp that left the group simply breathless. It was great. He went through all of the basics with wit, charm, and knowledge. I even forgave him for his quips on Scheme (which he knows that I love). He mainly stayed on the language and ventured a little bit into history (but, really that could be a two hour plus discussion in itself). All in all, if you missed it, shame on you! In the meantime, I'm going to work on Sam to do a sequel. Two hours is too short on such a cool subject.

The next meeting looks to be equally great: Python and XML by Mike Hostetler. See you all there!

Hard Week

This has been a hard week for me. It started out hopeful just to turn out worse than I ever expected. Oh well, life goes on. On to more positive pastures right? So, what better way to wash away the blues than color it RED! Yep, I'm going to RubyConf! This should be so much fun and I finally get to meet all of those cool Ruby enthusiasts! I can't wait.