Sunday, September 23, 2007
I'm embarrassed
And to end I will add, yes, Ruby does need tools. It needs tools badly. I would love to have refactoring support (that works) and a good debugger. I can't imagine doing a project of any size without those tools. Not every one is a great developer and eventually you will step into some unsavory code. Tools are for helping with those unsavory pieces of code and even to gain understanding on a large system. This is where learning comes in. Instead of writing the developer off as a "moron", I use unsavory code and tools to teach how to do it better. So, who's really "making the world of software development a more enjoyable, productive place"?
Sunday, September 16, 2007
A Sorting Language
class Comparator
def initialize(&default)
if (defined? default)
@compare_block=default
else
@compare_block=lambda { |a,b| a <=> b }
end
end
def compare(a,b)
@compare_block.call(a,b)
end
def to_proc
method(:compare).to_proc
end
def to_comparator
self
end
def then_by(next_aspect)
next_comparator=next_aspect.to_comparator
self.class.new do |a,b|
comparison=compare(a,b)
if (comparison == 0)
next_comparator.compare(a,b)
else
comparison
end
end
end
def reverse
self.class.new do |a,b|
comparison=compare(a,b)
if (comparison == 1)
-1
elsif (comparison == -1)
1
else
0
end
end
end
end
def by(aspect_to_compare)
aspect_to_compare.to_comparator
end
class Symbol
def to_comparator
Comparator.new { |a,b| a.send(self) <=> b.send(self) }
end
end
module Enumerable
def to_comparator
inject do |thus_far, every|
thus_far.to_comparator.then_by(every.to_comparator)
end
end
end
require 'rubyunit'
class SortTest < Test::Unit::TestCase
def test_simple
a=Person.new("blaine", 36)
b=Person.new("blaine", 12)
result=[a,b].sort(&by(:name).then_by(:age))
assert_equal([b,a], result)
end
def test_array
a=Person.new("blaine", 12)
b=Person.new("alice", 12)
result=[a,b].sort(&by([:age, :name]))
assert_equal([b,a], result)
end
def test_reverse
a=Person.new("grue", 123)
b=Person.new("thief", 34)
result=[a,b].sort(&by(:name).reverse)
assert_equal([b,a], result)
result=[a,b].sort(&by(:age).reverse)
assert_equal([a,b], result)
end
end
class Person
attr_reader :name, :age
def initialize(name, age)
@name=name
@age=age
end
end
I loved Neal's post, but it got me thinking that sometimes I need to sort beyond one field. How could I go about that? I whipped up this example really quick. The function :by is simply syntactic sugar for converting to a comparator. I thought it read better. Neal's solution is the way to go if you need to sort on a single field. But when you need more, the above will work too. This is another one of my little late night coding thoughts. Enjoy.
Saturday, September 15, 2007
Duh....
[1,2,3,4].inject() {|a,b| a + b} # 10
So, I looked it up in ri and got this entry:
------------------------------------------------------ Enumerable#inject
enum.inject(initial) {| memo, obj | block } => obj
enum.inject {| memo, obj | block } => obj
------------------------------------------------------------------------
Combines the elements of _enum_ by applying the block to an
accumulator value (_memo_) and each element in turn. At each step,
_memo_ is set to the value returned by the block. The first form
lets you supply an initial value for _memo_. The second form uses
the first element of the collection as a the initial value (and
skips that element while iterating).
# Sum some numbers
(5..10).inject {|sum, n| sum + n } #=> 45
# Multiply some numbers
(5..10).inject(1) {|product, n| product * n } #=> 151200
javascript:void(0)
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo,word|
memo.length > word.length ? memo : word
end
longest #=> "sheep"
# find the length of the longest word
longest = %w{ cat sheep bear }.inject(0) do |memo,word|
memo >= word.length ? memo : word.length
end
longest #=> 5
Ouch. All that coding for nothing (well, I did get to play around with some stuff). Next time, I will consult the documentation before I post. Duh...Good call.
P.S. It seems Rails implements the Symbol extension of #to_proc already. It's in the activesupport stuff. Their implementation is similiar to mind. But, I found one implementation better than mine. I love reading other people's code because it always shows me things I didn't think of. For your reading pleasure:
class Symbol
def to_proc
lambda do |this, *arguments|
this.send(*arguments)
end
end
end
This is better than using shift and cleaner. I got this from one of the comments off of Neal Ford's blog. Great stuff.
Friday, September 14, 2007
More Functional Fun In Ruby
def pair(left,right)
lambda do |dyadic|
dyadic.call(left,right)
end
end
def left(pair)
pair.call(lambda {|left,right| left})
end
def right(pair)
pair.call(lambda {|left,right| right})
end
require 'rubyunit'
class WorkspaceTest < Test::Unit::TestCase
def test_simple
a_b=pair('a','b')
assert_equal('a',left(a_b))
assert_equal('b',right(a_b))
end
def test_again
a_b=pair('a', 'b')
c_a_b=pair('c', a_b)
assert_equal('c', left(c_a_b))
assert_equal('a', left(right(c_a_b)))
end
end
Python's Reduce, (Fun)ctional Programming, and Ruby
module Enumerable
def reduce(empty_return=nil, &dyadic)
to_execute=lambda do |thus_far,every|
to_execute=dyadic
every
end
inject(empty_return) do |thus_far, every|
to_execute.call(thus_far,every)
end
end
end
require 'rubyunit'
class ReduceTest < Test::Unit::TestCase
def test_simple
result=[1,2,3,4,5].reduce {|thus_far,every| thus_far + every}
assert_equal(15, result)
end
def test_empty_nil
result=[].reduce {|result,every| thus_far + every}
assert_nil(result)
end
def test_empty_default
result=[].reduce(0) {|result,every| thus_far + every}
assert_equal(0, result)
end
end
It has a somewhat functional style in that instead of using a boolean to check for the first iteration, I just use a special lambda for the first pass and then it turns itself into the original one. There is some state (to_execute), but I'm still a functional newbie.
I do love inject, which has a lot of uses beyond aggregation, and this will reduce (no pun intended) code in some places where I use it.
Anyway, I couldn't stop myself. I thought wouldn't it be nice to just pass in a symbol instead of a block? I added the following method to Symbol and another test. Check it out:
class Symbol
def to_proc
lambda do |*arguments|
arguments.shift.send(self, *arguments)
end
end
end
class SymbolTest < Test::Unit::TestCase
def test_simple
result=[1,2,3,4,5].reduce &:+
assert_equal(15, result)
end
end
All I do is take a list of arguments. I make the first one the receiver and send the rest as it arguments. How cool is that? I get to cut down on the line noise. I still have to put up with &, but until they make blocks first class citizens...
What's the point of this post? Nothing. Just wanted to do a fun little exercise. I thought others might find the implementation fun as well. Now, about that name 'reduce'...I think maybe aggregate would be better? But, that doesn't express for all cases either. Hmmm...
Monday, September 10, 2007
Why Is Groovy So Slow?
But, that's not the point of this post. I'm worried with posts like the above because developers will use it as evidence that you shouldn't use dynamic languages. I never thought the arguments for not using dynamic languages would be played out again. Back in the 90's, it was Smalltalk vs. C/C++. I remember having many a debate how the productivity gains out weighed the small performance hit for late binding. I thought when Java won, I would never have to argue about performance ever again.
It's not that the above posts are bad. I think they are wonderful. It gives something that the Groovy guys can use to make their product better. And that's good for all of us wanting to be dynamic in a static world. But, those numbers will also be used to prove why you shouldn't use dynamic languages. And that's sad. It's all come full circle. I hope I am wrong, but I doubt it. The numbers are not bad because dynamic languages are slow, but because trying to get them run on an architecture not built with them in mind.
We Need Each Other: Ruby and Smalltalk
I'll start with a quote from Neal Ford:
the Smalltalk version is a great example of accidental complexity, not essential complexity.
There is no example given of what the "accidental complexity" was in Smalltalk. But, let's look at an example that Rubyists are familiar with and then I'll go forward:
class Person
attr_accessor :name
end
This will generate the accessors :name and :name= at run-time. It's a nice way to describe a public field. There's even read and write only variations. It allows you to describe your intent of the field. Now, in Smalltalk you could do the same thing with class-side methods. Like so:
attributeAccessors
^#(name)
This could add the instance variable (if it didn't exist), and generate the getters and setters when the class is initialized. It is true in this case, we would use tools to do the generation and generate the code before hand. I think this is what Neal was talking about accidental complexity because we are adding methods that we later have to browse through. But, this is where they are mistaken.
Smalltalk has categories and usually, these code generated methods are placed in them. Accessors are generally placed in their own category so do not add to the cognitive friction. In fact, when I use code generation, I group the methods in a category with "AUTO" in it. This is so that I can later delete those methods and start over. Also, it allows me to not have to look at them when looking at the more important methods of the class.
There is one last way to do things like this in Smalltalk, but is rare. Classes are created in Smalltalk by sending messages. It's not some hard-coded construct in the language. It's a message. We can create our own messages to create our own classes. Here's what the example could look like in Squeak:
Object subclass: #Person
attributeAccessors: 'names'
classVariables: ''
poolDictionaries: ''
category: 'MetaExample'
And lastly, there is a initialize method for all Smalltalk classes that would give a more Ruby feel:
initialize
self attributeAccessors: 'name'
Now, with all of that said, these are just examples to show what is possible. It's all a matter of taste and what you are trying to accomplish to which method you choose.
finally, my mouth dropped when I saw this in the same blog post:
Smalltalk had (and has) an awesome environment, including incredible tool support. Because the tool is pervasive (literally part of the project itself), Smalltalkers generally shied away from the kind of meta-programming described above because you have to build tool support along with the meta-programmed code. This is a conscious trade off. One of the best things about the Ruby world (up until now) is the lack of tool support, meaning that the tools never constrained (either literally or influentially) what you can do. Fortunately, this level of power in Ruby is pretty ingrained (look at Rails for lots of examples), so even when the tools finally come out, they need to support the incredible things you can do in Ruby.
I will answer this as bluntly and respectively as I can. Smalltalkers have NEVER shied away from meta-programming because of having to build a tool. Most Smalltalkers have a bag of tools that they use and add to their environment. Tools are so easy to write in Smalltalk that most programmers in it have at some point written one or two to help them. It's trivial to add functionality to the browser and inspectors. Generally, Smalltalkers only stay away from things that are hard to debug (ala method_missing, doesNotUnderstand:), but do them when necessary. Readability is always the utmost importance to Smalltalkers. Abbreviations are generally frowned upon even.
The last thing I want to remark on is the quote in bold above. I'll repeat it here because it makes me both shocked and sad:
One of the best things about the Ruby world (up until now) is the lack of tool support
I hardly call that a strength. Really. Why would I want to go back to bear skin and stone development? I have finally become productive in Java because of Eclipse (code browsing, auto-format, code completion, refactoring, etc). Why would I want to go back to command line brute force methods? I keep hoping for a great Ruby IDE (some are close like Ruby's Eclipse plug-in, Arachno, etc). Besides, I think while tools like ri and rdoc are nice, I want to look at source code and it's difficult to find the definitions of methods (without using grep) when going through new source code. A friend once told me he never trusted a language you couldn't write an IDE for it. There's truth to that. I never got FreeRIDE to last longer than a few minutes of development. Tools and easy to read syntax are necessary.
Ruby has great potential, but the syntax needs to be heavily reafactored (%w while being nice shorthand is unreadable) and made more consistent (blocks do not take the same types of arguments as methods, I can not send a block with & into a block example, lambda {|&block| block.call } gives a compile error). But, those are my gripes and I do still like Ruby. I think boasting that your language has no tools is short sighted at best.
I think both Smalltalk and Ruby developers could learn a lot from one another. So, if any Ruby developer has questions about Smaltallk, please feel free to email me. I will even extend the same to Smalltalk developers curious about Ruby. The point of this post was mainly to educate and inspire both Rubyists and Smalltalkers to be better.
Saturday, September 01, 2007
Omaha Dynamic Language Group
I hope to see everyone there!
| Topic | Rexx: The Little Known Scripting Language |
| Speaker | Scott Hickey |
| Time | September 4, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Tuesday, August 28, 2007
String Concatenation
def test_independence
first = "3" + "4"
second = first + "5"
third = "2" + second
assert_equal("34", first.to_s)
assert_equal("345", second.to_s)
assert_equal("2345", third.to_s)
end
Ouch. I fixed it by making DelayString only know a left and a right part. It cleaned the code up quite a bit. I factored out Promise because it made the code a little less readable. The resulting code is much simpler:
class DelayString
def initialize(oneString, anotherString)
@left = oneString
@right = anotherString
end
def +(another)
DelayString.new(self, another)
end
def to_s()
return @result unless @result.nil?
to_process=[self]
@result=String.stream_contents do |out|
until (to_process.empty?)
current=to_process.pop
current.process(to_process,out)
end
end
end
def process(to_process,io)
to_process.push(@right)
to_process.push(@left)
end
end
class String
def self.stream_contents(&monadic)
StringIO.open() do |io|
monadic.call(io)
io.string
end
end
def +(another)
DelayString.new(self, another)
end
def process(to_process,io)
io << self
end
end
All of our tests run. DelayString is stateless (minus caching of the result). There's still improvements to be made, but the code is simpler and easier to understand. The performance did take a hit. It's twice as slow (43.94s) as the previous version. Not to worry it still beats normal concatenation by a large margin. I'll take the performance hit for more readable code anyday!
Saturday, August 25, 2007
Promises And String Concatenation
Messages are the power of objects. So, why not make a new object that when sent the + message, it simply returns an object that waits to do the concatenation until it is needed. This new kind of object should understand the same protocol as string. This could all be handled underneath the covers. If it was done at the VM or compiler level, programmers would never have to know.
I thought I would do a sample implementation. It's rather easy (in a dynamic language). First, we need to implement a Promise class and here's the Ruby code complete with a simple test:
require 'rubyunit'
class Promise
def initialize(&block)
@calculation=block
@value=nil
end
def value
return @value if @calculation.nil?
@value=@calculation.call()
@calculation=nil
freeze()
return @value
end
def value?
@calculation.nil?
end
end
def promise(&block)
Promise.new(&block)
end
class PromiseTest < Test::Unit::TestCase
def test_simple
promise = promise { 3 + 4 }
assert(!promise.value?)
assert(7 == promise.value)
assert(promise.value)
end
end
Pretty simple, huh? Create a new Promise object on a block (or closure or lambda or whatever you like to call it) and it will only call the block once when the message "value" is sent to it. If the message "value" is never sent, the block is never evaluated. Can you think where that might come in handy? I can think of several, but the best one is when trying to create a message to log. If you don't log the message, you wouldn't need to do the concatenation. Again, not doing the computation upfront can not only allow us to manage memory better, but also not to do needless calculations.
Enough talk, let's get to the good stuff, right? Here's my implementation of delaying concatenations and check the tests out at the bottom:
require 'stringio'
class DelayString
def initialize(oneString, anotherString)
@strings = [oneString, anotherString]
@promise = promise do
stream = @strings.inject(StringIO.new) do |output,each|
output << each
end
@strings = nil
freeze()
stream.rewind
stream.read
end
end
def +(another)
return another.concatBeforeDelayString(self)
end
def concatBeforeString(another)
@strings.unshift(another)
self
end
def concatAfterString(another)
@strings.push(another)
self
end
def concatBeforeDelayString(another)
strings_each do |each|
another.concatAfterString(each)
end
another
end
def concatAfterDelayString(another)
another.concatBeforeDelayString(self)
end
def to_s()
@promise.value()
end
private
def strings_each(&block)
@strings.each(&block)
end
end
class String
def +(another)
return another.concatBeforeString(self)
end
def concatBeforeString(another)
another.concatAfterString(self)
end
def concatAfterString(another)
DelayString.new(self, another)
end
def concatBeforeDelayString(another)
another.concatAfterString(self)
end
def concatAfterDelayString(another)
another.concatBeforeString(self)
end
end
class DelayStringTest < Test::Unit::TestCase
def test_simple
add = "3" + "4"
assert_equal("34", add.to_s)
end
def test_string
add = "3" + "4"
add = "2" + add
add = add + "5"
assert_equal("2345", add.to_s)
end
def test_delay
add_before = "1" + "2"
add_after = "3" + "4"
add = add_before + add_after
assert_equal("1234", add.to_s)
#make sure to get same answer twice
assert_equal("1234", add.to_s)
end
end
One new class called DelayString handles not doing the concatenation until absolutely necessary. It does this by creating a Promise that calculates the string by using a StringIO object (Stream or StringBuilder in Java terms). All it does is keeps a collection of all the strings it needs to append to one another. The power is now that we get the nice succinct message "+" and all of the benefits of using a stream object (or StringBuilder). Of course, we would need to add more methods on our DelayString so that it has the same protocol as String. A little more work to make our implementation seamless.
Below is the test method I added to find the times it took to run for delayed and normal concatenation:
def test_performance
add = ''
1000000.times do |iteration|
add = add + 'a'
end
add.to_s
end
The new delayed implementation ran at 23.8 seconds. Not bad to do a million additions and a lot of little ones at that. Now, what were the results the old way? Well, all you have to do is comment out the + message:
# def +(another)
# return another.concatBeforeString(self)
# end
It took 4565.68 seconds to run the normal way. It performed poorly and took up a bunch of memory. Yuck. It's what the books warned us about right? It's what we expected somewhat. I didn't expect how much of a performance gain I really got. Pretty cool, huh? Amazing.
It's unlikely that we'll do something to this extreme in the real world. But, wouldn't it be nice to not worry about performance in our regular code? If we find that our implementation is sub-par, one of the new benefits is that we can change it in one place.
Wait a minute. We just got better performance and got to keep the simple way of doing things? Not one lick of our already existing code had to change. The power of messages is powerful indeed!
Saturday, August 18, 2007
Quiet Lately
Saturday, August 11, 2007
My Favorite Smalltalk is Gone
I realize it's hard to make money in the software development tools business. My own business failed as well. I was hoping for Dolphin to stick it out. Good luck to the Dolphin guys. I just want to thank them for all the love they put into the world. Dolphin will always have a special place in my heart. It will be hard to say good-bye.
Well, there's no reason for me to stay with Windows anymore now.
Friday, July 20, 2007
Sign Your Real Name
Monday, July 16, 2007
Bad Code
Sunday, July 08, 2007
My Job Went To India
Besides, if it was a joke, it wasn't funny. Scare books are cheap shots and not worthy of anyone's money. So, if they are wondering why sales were poor, I gave my reason. I trust Sam and I will probably buy it now. What a marketing mistake though.
Smalltalk Obstacles
- Different World Image-based development is strange to most developers. Also, Smalltalk forces developers to drop all of their pre-existing tools to play in this magical world. It's a lot to give up.
- Different Syntax Smalltalk's syntax baffles a lot of developers because it's so different from anything else. Most of what they have seen has been Algol-based. But, I've never seen a developer not understand it within a few minutes, but it is a hurdle for folks. This hurdle will always be there. Changing the syntax would make Smalltalk not Smalltalk.
- Unwillingness to compromise Smalltalk is powerful and the integrated tools is what makes it powerful. But, a little compromise to help developers dip their toes would help. At least allow to have some sort of training wheels before they jump in all the way. We need to allow them to test the waters.
But, the new obstacles along with the old ones are:
- We no longer have the largest library It's incredible the amount of open source libraries that Java and Ruby has. It's especially true for Java. It's enormous. Anything I want and it's been done. From database mapping to GUI to XML to you name it, it's just a source forge click away.
- Dated All dialects besides Dolphin look dated. There's no pizazz and simple things like consistent key bindings are not there. It's all a matter of polish and it shouldn't matter, but it does to a lot of developers. Sad but true. Looks matter.
- Tutorials There has been movement in this area recently in both Squeak and Visual Works. It's great and we need more.
- Marketing All of the Smalltalk web sites look old. Some graphic designers would go a long way. Ruby on Rails got to the top of the heap and exposed Ruby because of great marketing. I was programming in Ruby before Rails and it had none of the benefits of Smalltalk. We have a strong community, but marketing wins. Java kicked our butts once and at the time, we had the best libraries, environment, and everything. Marketing is king.
Now, that being said, I think a better looking Squeak, VisualWorks, and VisualAge is a must. I think they should all look at Dolphin. Dolphin is everything a modern Smalltalk should be. It's gorgeous. The key bindings are consistent, tools are easy to understand, and it's a pleasure to work with. They are also constantly adding new tools to help productivity (IdeaSpace) as well. In fact, I usually show developers Dolphin first to get them interested.
I think a good looking GUI is the first step. But, I also think making it easy for developers to use Smalltalk as a scripting language is a must too. We need to allow for developers to ease into image-based development by using their own tools. Yes, they will be less productive, but consider it to be an olive branch somewhat.
If we are to get more developers interested, we must come a little to them. I tried writing a scripting like environment for Squeak to make it easier for developers outside of Smalltalk to code in a more scripting style. And I keep playing with syntax to keep the simplicity, but also things to developers from the outside more comfortable.
And last but not least and this is a deal breaker: libraries. Seaside is a huge advantage, but we need more libraries that not only do cool things, but practical things as well. We have a lot of growth needed in this area.
The Ruby community has done a great job at showing off what you can do with pure objects and closures. Now, let's make it easy for them to see why an image and integrated tools make your live easier! We need to get off our island and start mingling with everyone. I created the Omaha Dynamic Language User's Group in the hopes to show developers what makes Smalltalk great(along with other dynamic languages as well like Lisp).
Friday, July 06, 2007
Crabs In The Pot
I feel Smalltalkers should stop complaining (about bad marketing, java, ruby, whatever) and start doing. Steve took a bold step forward and I applaud him for that. We need to have more doers and less complainers. So, if you feel marketing of Smalltalk is not up to par, do something! I started a user's group here in Omaha to get interest in dynamic languages. It's been growing larger and larger. The user group has gotten a lot of people interested not only in Smalltalk, but Lisp as well. But, I know I could do more. Steve is an inspiration and incredibly enthusiastic. If we want people to join us, we need to support the group we have now. Feedback is good and welcome, but if you feel you can do better....Well, then DO!
I didn't mean for this come out like I'm being harsh on Ramon. I don't want that. I love Ramon's writing and by having a blog, he is doing. But, I think we need to be reminded our community is small and we need to support one another. If Squeak is ugly, let's do something about it!
I wonder who will write the next tutorial on how to make Squeak look awesome? Whoever it is rock on! And I hope Steve does more tutorials, the laser game is too much fun. It shows how playful and curious Smalltalkers are and that's a great thing.
Thursday, July 05, 2007
Omaha Dynamic Language Group
We are sponsored this week by none other than Bass. They will bring the food and beverages.
Intelligent conversation, great food, excellent company, and it's all free. Come and see that the fuss is us.
| Topic | Bioinformatics and Perl |
| Speaker | Jay Hannah |
| Time | July 10, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Tuesday, July 03, 2007
Subversion
More on Exception Handling
I complete agree with you Blaine about not throwing away information. Keep everything, and add to that information whenever you have something to add. For example, when a caller catches an exception, the caller always has some indisputable and unique information it can add: exactly what it was trying to attempt when the failure happened.
Dropping this information is like using a shredder. It's not responsible behaviour for developers to shred information that might be useful to the poor sod who had to fix your buggy code at 4am in a production environment.
Actually, such information is often the 'single golden clue' that leads to a rapid diagnosis of the error. For this reason, I believe it's justified to add such information even when unchecked exceptions occur. "Yes, you got a NullPointerException, but what exactly were you trying to do when you caught the NullPointerException?"
For that reason only, I disagree with you about catching only the most specific exception- I always catch, wrap and rethrow any subclass of java.lang.Exception. I started handling exceptions in Java this way back in 1997, and haven't seen anything since that has caused me to change my mind (but I'm open to debate).
What a great idea! I love it. I agree if you are checking for generic exceptions and then wrapping them into more domain specific for more information, then rock on. My original comment was aimed at catching generic exceptions in your code and then doing nothing with them. I still generally try to catch the things that I expect to go wrong and use my top level to catch things I didn't. Always adding more information is a good idea in my opinion especially if it gives you more context. As with any rules, it really requires thought and good judgement to make a good program right? Thanks for the suggestion!
T.H.O. Part ][
I think that we a few more people with that T.H.O. attitude to prevent open-source libraries from stagnating. It is a good thing that the incumbent 'standard' library gets regularly challenged by contenders. Without continual selection and reselection, evolution dies and progress stops.
The argument that we only need just one of anything is really unhealthy. It leads to mediocrity: I present J2EE as a perfect example. One of everything you could possibly want, put it all together and what do you have? Crap.
I think you might have misunderstood me or I didn't make myself clear. My point is if you have want to do something better, then do it in the open source community. Go at it and have all the fun you want. I think the open source community needs and thrives on forward thinkers. At least there, you will have feedback, tons of people testing, and a chance for your idea to mature. But, I believe doing that on a corporate project is risky and prone to maintenance nightmares. Why? Because generally they have not gone under the same scrutiny an open source project has.
When I learn some new technique or have some crazy idea, I write it in my spare time. If I like it, I'll publish it on my site. Now, there's a lot of things that I did (like LazyCollections) that I would never do on a real project. Why? Well, LazyCollections was a chance for me to play around and try things out. I thought the experiment might be a helpful learning exercise to other people. But, the code is generally hard to understand for most developers.
I have empathy for the people that will have to maintain my code. Generally, this means I don't code things that I can, but what can be easily tested and maintained. It's not dumbing down the code or the design. Simple designs don't need tricks. They just need thought and lots of it. Simple designs are not easy and generally not the first solutions you come to. They are hard work.
Monday, July 02, 2007
Good code tells you where it hurts
try {
...hard stuff here...
} catch(Exception problem) {
problem.printStackTrace();
}OK, first off, I'm usually skeptical of catch all blocks at low levels. But, there can be good reasons for them, but the problem I have with code above is printing the stack to the standard out and continuing. At the very least, this is only good for when you are doing command line utilities and even then it's not good. Worse yet, this is the default from Eclipse! I've been bitten too many times where code went wrong and we couldn't find out why because the stack was written to the standard out and we couldn't see what it was. Or maddeningly the code continued and caused other problems further down. Fun to debug those problems it really is. My solution is if it's informational and you can continue log it, if not re-throw the exception. But, there's times when you catch a checked exception, but it's something that's serious enough to stop current processing. I've seen this:
try {
...something hard here...
} catch(Exception ex) {
throws new RuntimeException("Something bad happened");
}Thankfully, I haven't seen the above code so much since 1.4 added support for wrapped exceptions. But, I still see it. The problem with the above is the original exception is dropped. When debugging or trying to find a problem, the above code gives me no information of the original context. It's useless, but it did stop bad things from happening further down. But, it would be almost possible to find out what really went wrong.
Always catch the most specific exception and leave the catch all exception handlers to the top level code. It will save you headaches, I promise you.
My rule of thumb to exception handling is: if something goes wrong, what would I want to know? I see too much code where this is forgotten or it is written as if nothing will go wrong. In a perfect world, all code works beautifully and there is no need for exception handling, but we don't live in that world. As always think about helping the poor developer that has to come behind you.
T.H.O.
Tuesday, June 05, 2007
"Get 'Er Done" Programming
Alright, you might ask what does "look at the big picture" mean exactly? What I mean is do proper analysis. Think about your problem before you write any code. I'm not advocating huge up-front design here, just thinking before you burn up your keyboard. It might also entail asking a few questions about the problem to fellow team mates and the user. It all depends on what your coding and your understanding. Looking at the big picture also means in making your code to be able to have future extensions that you can't anticipate. You might think this is impossible, but it's not. If you make the objects small, each one has a single responsibility, have good intention revealing names, and make small methods, then you have made your code extensible.
The whole point of this blog post is don't be lazy and make life difficult for the person that has to come behind you. Think about what you're doing and make your code easy to read. Remember there is always someone coming behind you that has to learn what you did. Make it obvious and show that you cared by going beyond the simple example. Well, looking back this wasn't so bad was it? Sometimes rewriting and thinking about what you write works too.
I'll end with a piece of advice: always re-read your code once you have written it and it works. You would be amazed at what you catch (misspelled words, uncalled methods, unused variables, etc). Of course, with today's tool this is quite easy. In fact, Eclipse can flag most of these with a warning, but it's still a good habit to read your code before you check-in. Let's stop "Get 'Er Done" coding today. Besides, only idiots write code that way and I know you are not an idiot, right?
Tuesday, May 29, 2007
Omaha Dynamic Language Group
This month we are also honored to have Concentric sponsor us! They will be providing food, drinks, and much merriment. We are glad for their participation.
I will see you all there for the greatest user group ANYWHERE!
| Topic | Cold Fusion |
| Speaker | Ryan Stille |
| Time | June 5, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Friday, May 11, 2007
Jargon
Idea Killers
The mantras were meant to shake your thinking. How could you do this as simple as possible and still work. A nod to good engineering and design to shake the brain to think of another solution. Or ask questions like "Do you really need that huge framework?" But, lately, these mantras have been having the opposite effect. I've been in meetings where they were used to shoot down good ideas. And they work well. It's hard to argue against. You don't want to be the person that doesn't want the simplest solution right? But, when you are at the phase of generating ideas, these critical phrases kill the creative spirit. I say no more.
I say no more mantras. Let's think. Let's generate ten great ideas and then be judgmental of each one. At the idea phase, all ideas cost the same. Crying "It's not the simplest thing" too soon kills good design thoughts dead before they are allowed to grow. I think these phrases have become too common place. They are used to shut off thought and prove you are right. Besides, it's been a rare event when someone meant truly simple and not easiest. The two are confused frequently. Simplicity takes practice and thought. There's a reason why Einstein said it. It took several rewrites to get Smalltalk to its current state of simplicity.
Think about it. Refuse the use of mantras. And let ideas flourish.
Truth, Justice, And The American Way
if (transaction.amount) {
transaction.markValid();
} else {
transaction.markInvalid();
}
Nothing wrong here, from the looks of it the code is checking if the transaction has an amount defined and then marks the transaction valid or invalid. Simple right? But, what if an amount is defined and it is zero? You would think the transaction is marked valid right? WRONG! It will be marked invalid because anything that's zero, nil, or undefined in Javascript is considered false.
And that's my beef, why not treat booleans with their own type. Why treat any other value as equivalent? Subtle bugs like the one above are infuriating to me. The simple reason is that they can easily be avoided with a few extra characters.
if (transaction.amount == undefined) {
transaction.markValid();
} else {
transaction.markInvalid();
}
The moral of this story is to code exactly what you mean. Be specific. Don't rely on arcane language features to save a few key strokes. Java and Smalltalk do the right thing and make you use boolean types.
Wednesday, May 09, 2007
I Can't Stand Pretentiousness
I guess it's my southern upbringing. I like simple things, but I also enjoy richer experiences as well. I just hate it when someone is not open to the joys of the simpler things. I listen to all kinds of music, food, or what have you. I will try anything once. And I research any language I can get my hands on. They each have their strengths and pluses.
Now, don't mistake pretentiousness with excitement. I love excitement and a healthy jubilation for your newest discovery. But, when it turns to thumbing your nose at something, then I think the coin has been flipped.
Oh well, I had to get that rant off my chest. I'll probably read it tomorrow and go "What the hell were you thinking?!" Or maybe I was just trying to say, "There's something positive about everything, find it", in a really negative way.
Live Refactoring May 15
Sunday, May 06, 2007
DSLs: What's the big deal?
But, I should really be kicking myself. I should be glad that good design is back in vogue. and you know what? I am. I'm not annoyed any long and I relish all of this new talk on DSLs. I even feel guilty. You see, DSLs have always been part of the Smalltalk farbic. It's natural to us because it's the way we have learned to code. I remember having the mantra "Code should read like a conversation" shoved down my throat until it became second nature. The cool thing is that there is a whole new generation finding out about this and doing it. Very cool.
I'm now promising myself to show non-Smalltalkers the other cool things that we have in our fabric and what we take to heart. The power of messages compels thee!
Groovy: Java 7?
Sunday, April 29, 2007
Built-in Persistence/Transactions
Gemstone is the realization of this on the server. It would be nice to make the code on the client as transparent as well. I know some might laugh at this idea, but I think it has merit. Just like garbage collection seemed strange at first, why not allow automatic persistent management as well?
Re: Make Debugging Tests Easy
Can you give a more specific example please? I don't see anything wrong with this, for instance,
| file |
file := self loadPaymentFile: self sample.
self assert: file validPayments size = 3.
self assert: file invalidPayments size = 1.
Well, I would probably change the file to a stream, but that's a different topic and discussion (I generally don't like to access outside resources in my test; they only cause problems later). Back to the conversation, the last two lines are what I don't like. The reason is that say another developer changes any of the code that gets called during the loadPaymentFile: and they run all tests. And let's say it's in common code and this test fails. Let's also say that we get back 2 valid payments and 2 invalid payments.
The developer is going to have no clue which one became invalid and what made it valid in the first place. You could put in comments explaining what the 3 valid payments and 1 invalid payment were to help. or you could break out and have several asserts for each of the cases. Otherwise, I have to revert code and rerun this test to see which payment is now incorrect. And then, put my code in and see where my code is incorrect. The above code makes the original intent hard to understand. Why were only 3 valid? Why was only 1 invalid and what made it invalid?
Really the above test is not incorrect per se, it's just not very thoughtful of the other developer's time. A couple of extra minutes of coding time would save the other developer a couple of hours. It's about coding and feeling sorry for the poor person that has to come behind you and figure out what you did. I try to always code with the maintainer in mind. Most times, the maintainer happens to be me and I'm always thankful I took the extra time to help myself.
Thursday, April 26, 2007
Omaha Dynamic Language User Group
Pizza, drinks, and a special prize (just like a box of Cracker Jack) will be provided for by this month's sponsor's Tek Systems.
Free food and stimulating conversation make for an exciting Tuesday night! See you all there.
| Topic | GData |
| Speaker | Brent Adkisson |
| Time | May 1, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Tuesday, April 24, 2007
Make Debugging Tests Easy
Think about it if I check that the size of a certain collection is 5. I can bet in 6 months the reason will be fuzzy. Of course, you could name the 5 as a constant and that would certainly make it more readable. It is a step in the right direction even. But, why 5? If I change code and I get back 7, what does that mean? A constant might help, but it might not. Be specific in what you check. Don't get lazy in naming or being general. Spell it out. It might take more effort now, but it will pay huge dividends when the test breaks. More than likely, when a test breaks after it is running that it is unexpected.
Feel sorry for the poor developer that has to change your code and then figure out your tests. Take as much care in your test code as your main code. You will be thankful later. Your tests will spell out exactly what's wrong, be easy to debug, and most importantly easy to be fixed again.
Thursday, April 12, 2007
Tiny Types, Abstract Data Types, And Little Objects
Tiny objects make unit testing easier, aid in reuse, stop duplication dead, provide for better messages when things do break, puts functionality closer to where it is used, and I could go on all night. The amazing thing is at first I started to use tiny objects to put constraint checking in so that it didn't get propagated everywhere. But, something strange happened. These tiny objects started to take on more functionality and have real protocols beyond just get and set of their values.
I think tiny objects are even more important in dynamic languages than in Java. They can make stupid programming errors easy to find and correct. Also, your functionality is spread across several single responsibility objects working in concert to provide complexity.
Tiny objects are good design period.
Tuesday, April 03, 2007
The Power OF Smalltalk Compels Thee
Thursday, March 29, 2007
Java VM Puts Shackles On Development Tools
But, this post is not about how foreign Smalltalk is to java developers, but how still in 2007 with dynamic languages finally getting recognition that few people are screaming for the capabilities of a Smalltalk VM. The productivity of Smalltalk owes not only to its dynamic nature, but to its always running and lively IDE. It's a living environment. Objects are alive and not dead. Why are there not other environments that do this? (OK, Lispers, I didn't forget about you...anyone else?) And why aren't these environments in the newer dynamic languages (Ruby, Python, Groovy, etc)? Have the shackles of the java runtime environment ruined us?
Or maybe the problem is just that we are always thinking of runtime and not development time. Java places a lot of barriers in the way of developers in the name of security. Why not have a specific VM purely for development? One that could dynamically load classes and code. One that could take snapshots of the running system and save the state for later. One that could compile incrementally and keep all of the bookeeping in order so that our tools stay snappy. One can dream.
Now, for Ruby and Python, there is no excuse. They have their own VM and why don't they support IDEs to implemented in themselves? Java, Groovy, and Scala have the excuse of the java VM. One of my hopes for Ruby was a Smalltalk-like IDE, but sadly, I don't think it will ever happen. The first step would be not to throw away the source code when they compile.
The thing that makes Smalltalk IDEs so cool is that they are alive. The VM supports object mutability and snapshotting state. The whole IDE is written in Smalltalk and is part of the live development system. You don't have to restart anything to try something out or shut down the everything to run a new tool. It morphs into what you want and let's you do what you want. No shackles.
This is what I want from the new generation of dynamic languages. I wonder how hard it would be to have a development java VM. Hmmm....
Omaha Dynamic Language Group
Want more? How about sponsorship from ProKarma, Inc. (eSymbiosis)! They will be providing us with a door prize, pizza, and drinks.
This is one exciting meeting that you can not afford to miss. I will see you all there!
| Topic | Flex/ActionScript |
| Speaker | Axel Jensen |
| Time | April 3, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Tuesday, February 27, 2007
Where Did Use Cases Go?
It seems in the rush for agility that people threw away use cases as well. I don't know why. I think stories are a horrible mechanism for understanding. They are the lazy man's use case. Modeling the main domain objects and a good cut at use cases is crucial before you start coding. It will save countless hours. Now, this might seem un-agile. But, thinking about your problem and trying to get a good grip on it before you start coding IS agile. Writing use cases does not end when you start designing or when you start coding. It's a continual process. Use cases are needed to be not only for the knowledge of the developer, but also so that the client knows exactly what you are building. They are to be done together. And as any experienced developer will tell you, you never know everything about what you're building. Customers and developers need each other. Use cases are proof of that.
Use cases rock.
Omaha Dynamic Language Group
| Topic | Domain Specific Languages |
| Speaker | Matt Secoske |
| Time | March 6, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Monday, February 26, 2007
Made it home...
- Seats in the airport should double as beds. And they should be more comfortable.
- There should be a stock of pillows for people sleeping in the airport when bad weather hits.
- Lower volume on the intercom. In fact, get rid of the damn thing. It's annoying and there's only so many times I want to hear about "orange" security level. Place more terminals with good information and have it be up to do date. The biggest problem over the weekend was lack of information. Rumors ran rampant and a terminal with information would have stopped most of it.
- No leaning back chairs on airplanes. They are simply a BAD DESIGN. They are good for one passenger and bad for another. Either that or make more room on the airplane.
- Don't lie. If you don't know the answer, tell me. If the answer is unpleasant, then tell me. Imagine my surprise when I was told that my luggage was following me through the cancellations, but in fact, it is still in Memphis.
Saturday, February 24, 2007
Stuck in Memphis
- Create more than one line. I would divide them up by flexibility of travel plans. I notice a lot of time is spent with just a few passengers. You could use one line to determine what the needs are and then pass them on to more dedicated lines. This would speed things up for everyone on the whole.
- Updated information on the boards. Most of the problem is that you don't know what's going and there's no confirmation that you're doing the right thing. It's chaos. Some road signs would answer most people's questions (flight delayed - for how long - and yep, it's canceled and with the reason!).
- Send flight information to your cell phone for each of your flights. If it gets canceled and they automatically rebook, then notify me. If the default is unacceptable, then I'll wait in line. But, give me options. I'm thinking the default would the best for most people and reduce the line size.
- "Feed" the line. People are generally tired, cranky, and hungry. Pass out refreshments while they wait in long lines. It will keep the natives peaceful.
- Workout a deal with a local taxi company to pick up the slack to take people to the hotel. I waited an hour tonight just to get to the hotel.
- Workout a deal with the tourism department to show around town if their flight is canceled. They have time to waste and might want to venture out.
- Have shuttles from the hotel that take people to malls or Wal-Mart. Why? Because you don't have your luggage and might want a fresh set of clothes.
- Have private areas in the airport. I would spend money just to have a small place to prop up my feet and take off my shoes. I'm thinking something with walls and a Laz-E-Boy chair.
- Better food. Airport food is expensive and junky. Sometimes I would give anything for some vegetables and something healthy. How hard can that be?
Sunday, February 04, 2007
Books on Design
- Designing Object-Oriented Software : THE book on OO design and analysis. This one keeps it simple and is awesome. Mrs. Wirfs-Brock will always be one of my heroes that I aspire to.
- Domain Driven Design: And I'm not saying this because of my involvement with TimeAndMoney. Eric is not a great mentor, but an awesome author. If you want to learn how to write REAL DSLs, this is the book. Learn to talk through your domain. Read this cover to cover. There is not one paragraph not to be savored. I went to the first Smalltalk Solutions just to meet him. Seriously...
- The Design Patterns Smalltalk Companion: This is the book where you learn a lot of the hidden secrets in Smalltalk and that all of the design patterns started there. This is an awesome book and reads better than the original. Buy this even if you don't know Smalltalk. It's that good.
- Structure and Interpretation of Computer Programs: I don't know one person who has read this and not have had the way they look at software be different. Learn to be a magician. This opened a lot of possibilities for me. It made me much more creative in my solutions.
- Prefactoring: A lot of Agile enthusiasts got upset with this book because they didn't read it. This book dares to followers to do what they say: Think about their designs. This is also a great book if you want to learn more about DSLs. All good OO models are DSLs. If you're not doing a language with your models, you are doing something wrong.
- Agile Software Development: Robert Martin hits a home run with this book. This is what people who think Agile is about no design, should read this. Being agile is about thinking. I know a lot of Agilists get that, but I have come across many who think it's all about coding and no thought. This book goes beyond Agile and talks about good ole great design.
- Software Fundamentals: These articles were written before I even knew what a computer was and they are still relevant today as they were then. You'll either walk away from this bewildered at what we keep rediscovering or notice how a lot of stuff that seems new is really rebranded. This book is just an awesome tomb of software experience from one of the early innovators. His views on encapsulation really changed the way I look at design. Awesome book.
- A functional pattern system for object-oriented design: Functional programming for object-oriented programmers. I love functional programming and by studying it. My thoughts on development and design have changed. This book shows that they both can share ideas from each other and become stronger. This is a fantastic book that should get more accolades. It shows what great things can be done if OO and functional programmers put their powers together for good.
- Every single book that Martin Fowler has had his name on or associated with. They all rock. Analysis patterns is really the crowning jewel (again, if you want to do DSLs, learn from the master). But, all of his books are easy to read and will teach you volumes.
Wednesday, January 31, 2007
Dynamic Language User Group Is Back!
Room PKI 269 is nice because it has about 25 machines, each connected to the Internet, and a large screen projector at the front of the room. A laptop may be connected to the projector or you can just use the PC at the front of the room. Almost every room in PKI has a large screen projector at the front of the room with a PC and a laptop connection. All of the rooms have white boards.
WOW! I would like to give extra special thanks to Heather Blockovich of Tek Systems for all of her help. So, when are we meeting at our bright new shiny place? February 6 is the date usual time of 7-9pm. Of course, I'm always up for a little chit chat before.
Now, for the most important announcement (drum roll please): the speaker! Ben Heath will be providing a special evening of discussion on Common Lisp and his Netflix project. Ben is a passionate programmer with years of experience and is a Lisp and dynamic language lover. It's going to be an exciting talk for sure! I can't wait.
And if that wasn't all, Tek Systems will be joining us with food, refreshments, and maybe a few suprises! Yes, we have sponsorship for this meeting. Now, I have to ask what better way to spend an evening with free food, great place, great people, and awesome Lisp coding?! It's just too good! I look forward to seeing everyone.
| Topic | Lisp and Netflix |
| Speaker | Ben Heath |
| Time | February 6, 7-9pm |
| Location | UNO's Peter Kiewit Institute (PKI) building 1110 South 67th Street Omaha, NE |
Sunday, January 28, 2007
Some Self Philosophy
In short, to maximize the opportunities for code reuse, the programmer should:
- avoid reflection when possible,
- avoid depending on object identity except as a hint, and
- use mirrors to make reflection explicit when it is necessary.
This is the summary to a portion of the chapter entitled, "Behaviorism versus Reflection". It's best explained in this three paragraphs:
One of the central principles of SELF is that an object is completely defined by its behavior: that is, how it responds to messages. This idea, which is sometimes called behaviorism, allows one object to be substituted for another without ill effect—provided, of course, that the new object’s behavior is similar enough to the old object’s behavior. For example, a program that plots points in a plane should not care whether the points being plotted are represented internally in cartesian or polar coordinates as long as their external behavior is the same. Another example arises in program animation. One way to animate a sorting algorithm is to replace the collection being sorted with an object that behaves like the original collection but, as a side effect, updates a picture of itself on the screen each time two elements are swapped. behaviorism makes it easier to extend and reuse programs, perhaps even in ways that were not anticipated by the program’s author.
It is possible, however, to write non-behavioral programs in SELF. For example, a program that examines and manipulates the slots of an object directly, rather than via messages, is not behavioral since it is sensitive to the internal representation of the object. Such programs are called reflective, because they are reflecting on the objects and using them as data, rather than using the objects to represent something else in the world. Reflection is used to talk about an object rather that talking to it. In SELF, this is done with objects called mirrors. There are times when reflection is unavoidable. For example, the SELF programming environment is reflective, since its purpose is to let the programmer examine the structure of objects, an inherently reflective activity. Whenever possible, however, reflective techniques should be avoided as a matter of style, since a reflective program may fail if the internal structure of its objects changes. This places constraints on the situations in which the reflective program can be reused, limiting opportunities for reuse and making program evolution more difficult. Furthermore, reflective programs are not as amenable to automatic analysis tools such as application extractors or type inferencers.
Programs that depend on object identity are also reflective, although this may not be entirely obvious. For example, a program that tests to see if an object is identical to the object true may not behave as expected if the system is later extended to include fuzzy logic objects. Thus, like reflection, it is best to avoid using object identity. One exception to this guideline is worth mentioning. When testing to see if two collections are equal, observing that the collections are actually the same object can save a tedious element-by-element comparison. This trick is used in several places in the SELF world. Note, however, that object identity is used only as a hint; the correct result will still be computed, albeit more slowly, if the collections are equal but not identical.
Basically, the above is basically placing more value on "duck typing" (the new word for behaviorism) than reflection. I've always placed myself in the "behaviorist" camp and anyone that knows me rolls their eyes when I rip into my "@#$%^& not another data structures and controllers architecture!" It's because I place more value on the behavior than I do the data. It has a lot to do with my mentors enlightening me to the teachings of the brilliant Rebecca Wirfs-Brock (yes, she is still my hero).
Sorry for my digression, but why did I quote all of this? First off, I always thought of duck typing and reflection as tools in my bag. I have never thought about why I would pick one over the other. I do tend to pick non-reflective solutions where I can (It seems Joshua Bloch does the same from his Effective Java book as well). The reason being that most people understand behavior, but reflection is not so obvious.
OK, enough background, and on to my real point. This all got me thinking about why I've always been squeamish with reflective GUI, persistence, and rule engine frameworks. Now, before I begin, I love my OO-relational mapping tools and rules engines, but somehow they have always seemed like they were breaking encapsulation. And in fact, they are for great benefit (which outweighs the encapsulation violations). They are going underneath the covers of your objects and exposing them to a privileged few. Now, this gives us great power and takes a lot of things out of our hands. These frameworks do a lot of heavy lifting and breaking encapsulation has always seemed like a small price to pay. But, how could we do it without reflection? Ah, there's an interesting question, no?
Is this mental aerobics going to get us anywhere? I don't know. But, I bet the journey will be fun. So, what do we have in our arsenal right now? Well, off hand you can name the Memento pattern and we could have a simple hash table object that we get values in and out of the object. This could work for all of the frameworks I listed. But, it seems cumbersome and still prone to major changes in the object topology. We're still depending on data, just putting a common interface on an object. Perhaps, this is the point of "Mirrors" in Self is to provide this type of functionality, albeit consistently. It's also slow because we have to keep taking snapshots if we want to track changes (which means we have to ask for the data and then do compares). But, we could use the Observer pattern and trigger events on any change to an object at the end of some change transaction.
Another tool can be found in Allen Holub'sexcellent article about alternatives to getters/setters in GUIs using the Builder pattern. Now, the solution is very specific, but it's a turn on the Memento pattern. I like that fact that it's more about behavior where I have to send an object that understands the messages and reacts to those messages instead of being passive. But, it still seems the Memento pattern wins because it can be more generic (at its simplest: get(key) and put(key, value)).
I'll leave this article as a point to ponder. There might not be an answer. But, I think a pure behavior approach is more understandable and simple than a reflective one. If anyone has any thoughts, please send them to me. I'll post any further thoughts as I have them. I'm always thinking of ways to preserve encapsulation in my designs. Just remember, Alan Kay wished he had called object-oriented programming, "message-oriented programming". It enforces the black box nature of objects and strong communication semantics. It keeps designs simple and easily reasoned about. Now, don't get me wrong, I don't hate reflection. I just feel like we should always seek alternatives, like inheritance it holds awesome power. But, in the wrong context can cause maintenance issues. Just because you have a tool doesn't mean you have to use it. Besides, forcing constraints on yourself, can cause interesting thoughts on your future designs.
Saturday, January 27, 2007
Smaller Is Better
"The smaller the object, the more forgiving we can be when it misbehaves." -John Maeda, "The Laws of Simplicity"
This quote was talking about real world objects, but I think it's doubly true for software objects. If we keep our objects small in our design (single responsbility), we will be more forgiving when errors arise. Why? Small objects are easy to test, debug, and well, fix. In fact, the fix is obvious because the object is so small. It's time to make our objects small and build layers of domain specific languages on top where each layer is simple to comprehend and understand. It would make our designs "more forgiving" to the ones who have to maintain it.
Magnetic Fields Metaphor
Magnetic Fields:
Find a central metaphor that's so good that everything aligns to it. Design meetings are no longer necessary, it designs itself. The metaphor should be crisp and fun.
Metaphors are a hotly debated topic in XP/Agile circles and I've never understood why. Alan Kay's quote resonates with me because when you have a good metaphor for your system, you can easily make design decisions as they arise. It keeps your design cohesive and simple. Of course, if your metaphor doesn't fit, it can have the opposite effect. I don't force metaphors, but when one pops that fits...I grab it whole-heartedly. But, I will take the time to brainstorm for one. The metaphor should be your compass that helps you navigate through your design decisions.
Language Of The Year
Sunday, January 21, 2007
Feed Change
I did make a few changes to where index.rdf will now still be updated from atom.xml in the meantime. Again, thanks for everyone's patience on this matter.
Wednesday, January 17, 2007
Java And Simplicity
I believe, simplicity of language is VERY UNDERESTIMATED asset.See, I worked for years with c++. I liked templates, they were
giving me a 'mental satisfaction'. I liked to check generated
assembler, emmited own instructions when not satisfied.But that's not way how programs should be made.
Once switched to java, I apprecitated simplicity of java.
Java followed KISS principle, provided simple language,
simple tools (javac, javadoc, javah ... ).Now, we are loosing this important asset.
Converted c++ programmers ask their templates and operators.
Converted c# programmers ask their properties and closures.
Coverted script programmers want their dose of language sugar.Java creators made java simple - and not simpler then it should be.
We should apprecitate and preserve it (in rational way).
OK, I'm sure that some of the Smalltalkers and Lispers out there either have their jaws on the floor or hurt bellies from laughing so hard. I know I did at first and then it struck me. We have failed. We have failed to educate on what simple can truly be. When I think of simplicity in language design, I think of Self, Smalltalk, Forth, and Scheme. Java wouldn't even come close. But, there's an army of developers out there that haven't seen better and that is sad.
Sure, we could easily laugh at the uneducated, but it's our fault. Instead we should be sharing and telling. I spent time at RubyConf showing off Squeak and have been known to hang out at the local Java user's groups talking all things dynamic. I enjoy showing people the power that's out there and the great thoughts that have preceded us. It's exciting to see Java getting some of these capabilities and programmers demanding them! The future is bright, but there are still some we haven't reached.
Next time, you hear someone call Java simple, don't snicker. Show them something simple. Who knows maybe someday I'll be able to program in Self because it will be the defacto standard. A boy can dream can't he?
Wednesday, January 10, 2007
Favorites Of 2006
- Unexpect-In a Flesh Aquarium
- Muse-Black Holes And Revelations
- Into Eternity-Scattering Of Ashes
- Pure Reason Revolution-The Dark Third
- Peeping Tom-Peeping Tom
- Axamenta-Ever-Arch-I-Tech-Ture
- Hammers Of Misfortune-The Locust Years
- Die Apokalyptischen Reiter - Riders On The Storm
- OSI-Free
- Ghoul-Splatterthrash
- Frost*-Milliontown
- AFI-December Underground
- Strapping Young Lad-New Black
- Mars Volta-Amputechture
- Dragonforce-Inhuman Rampage
- Estradasphere-Palace of Mirrors
- Cradle of Filth-Thornography
- Black Stone Cherry-Black Stone Cherry
- Trivium-The Crusade
- The Faceless-Akeldama
Tuesday, January 09, 2007
Zero Mass Design
He has a little book called "Zero Mass Design", the premise of which is that if you're going to work on something - for instance, you're going to write a book, or you want to write some software, or you are about to embark on any project that requires planning -- start with a simple design. But it's more extreme than just keeping it simple; you start with a design so simple that it won't work. That requires a great deal of discipline because you go into the project with the premise that you will fail; until you've tried something and actually seen it fail, yoiu don't know how simple you can get.
Does it sound familiar? Sounds sort of agile doesn't it? The explanation that he gives next is the best I've read for "Do The Simplest Thing Possible" mantra of XP. Read on:
Dave Thornburg's example, from James Adams' book "Conceptual Blockbusting", is the Mariner IV spacecraft. It had large solar-cell panels that unfolded. The problem, as stated, was to have a mechanism that slowed down the panels as they unfolded so that they wouldn't break when deployed. So, they tried oil, but that was sort of messy, and they tried springs; they did all sorts of things. The day for the launch was coming nearer and nearer. What were they going to do? Remember, the problem as stated was to find a way to slow down the panels, or to find a braking mechanism. Finally, somebody had the brilliant idea to try it with nothing, so they tried it and the panels shook and shivered but nothing broke. If you state the problem with assumptions, you're going to get them. You're got to pare back and pare back and pare back. Starting with a very simple design has wonderful advantages, but it requires a pyschological twist; you have to expect that it will fail and enjoy that.
I like to get requirements stated in goals which is a trick I learned from use cases. Get the problem stated as a goal and a lot of assumptions can be removed. You'd be surprised how well it helps. The point is not only to "Do The Simplest Possible Thing That Will Work", but state the problem as "Simply As Possible". It removes assumptions and thus, doesn't color your design with needless complexity. Those words slapped me in the face and it seemed everything came together. Wow.