Tuesday, June 3, 2008

Extreme Programming/Agile

When I first read about extreme programming, I became interested because it sounded like a software-development process which focused on honest communication between developers and the business. And even if that level of honesty produced working software at the same rate as waterfall, I prefer an honest process.

However, that's not quite why I like extreme programming and agile these days. Instead, I view the goal of enterprise software development to be the creation of personal dynamic media. While that goal has yet to be attained in most daily work, agile methodologies are much closer to that goal than many of the alternatives.

Wednesday, May 28, 2008

Dan Ingalls interview

Dan Ingalls is the MAN!

Wednesday, April 16, 2008

Tautology-Test Driven Development

It can be difficult to argue that the addition of comments to code can be helpful from time to time; even though one should strive for expressive, self-documenting code. Just like it can be difficult to argue against certain forms of test driven development.


Test Driven Development is a software development methodology which has received a lot of attention within the past decade, even within the most conservative of organizations. I sincerely believe the attention is well-deserved. Kent Beck's book on TDD was a real eye opener for me. His tests reflect what he wants to say, the implementation code follows. To ensure the robustness of the code, tests are triangulated; resulting in a solid domain model.

However, a non-negligible percentage of the tests I've observed in practice stray quite a bit from how Mr. Beck describes them. I call a subset of these Tautology Tests. In other words, the tests assert that the code does what the code does. I perceive the root cause of TTDD to be the absence of orthogonal persistence - the fact that the domain model is tied to external resources such as a relational database.

I'll use Ruby to illustrate my point. Not because development in Ruby necessitates tautology tests, it's just that stubs/mocks are easily created in dynamic languages.

When a developer cannot use orthogonal persistence, he is forced to mock/stub out quite a bit of code. It's not that mocks/stubs are a bad thing. But, instead of using the tests to drive the domain model, the developer ends up writing the implementation code twice.

For example,
test "that the code does what it does" do
foo = Bar.new
Baz.expects(:quux).returns([:answer])
assert_equal [:answer], foo.qux
end

The code is then implemented as:


class Bar
def qux
Baz.quux
end
end


If and when the code changes, what does the test tell you about the expected behavior of the qux method? It would have been difficult to argue, but a comment above the method would have expressed a lot more intent than the tautology test.

Saturday, March 22, 2008

Functional Collection Patterns in Ruby

This is a modified-rewrite of my Functional Collection Patterns in Java article, using Ruby.

While many software developers are familiar with the Iterator pattern from the classic ``Design Patterns'' book, the Iterator pattern just scratches the surface of the abstractions available on collections. Classic languages such as Scheme, Common Lisp, and Smalltalk-80 provide much more powerful abstractions over collections. These abstractions are available in Ruby as well.

The patterns listed in this post are all dependent on the availability of high-order functions. A high-order function is a function that takes in a function as an argument, or returns a function. By the end of this article I hope to show that the use of high-order functions is extremely useful for separating the collection's concerns from the user of the collection.

There are three main categories of operations on collections:
  1. Map
  2. Filter
  3. Reduce

Map

The Map pattern evaluates a high-order function on all elements of the collection. It returns a new collection with the results of each function application.




Filter

The Filter pattern evaluates a predicate (a function which returns a Boolean) on each of the elements, returning a new collection which is subset of the original collection.




Reduce

The Reduce pattern evaluates a function on all elements of the collection, returning a scalar value. For instance, in the following diagram, Reduce is applied to sum the area of each shape.





Ruby Examples

This section will show how to use Ruby's blocks as high-order functions to take advantage of the Map, Filter, and Reduce patterns.


High-order functions

High-order functions are realized in Ruby via block closures.


irb(main):001:0> class Foo
irb(main):002:1> def initialize
irb(main):003:2> @bar = 1
irb(main):004:2> end
irb(main):005:1> def modifyBar
irb(main):006:2> @bar = yield(@bar)
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> baz = Foo.new
=> #<foo:0xb7c2dde8 bar="1">
irb(main):010:0> baz.modifyBar {|bar| bar+1}
=> 2
irb(main):011:0> baz
=> #<foo:0xb7c2dde8 bar="2">


Map

Suppose I have a collection of lowercase letters that I want to convert to uppercase letters. Ruby implements the map pattern with the "collect" method.


irb(main):001:0> foo = ["a", "e", "b", "s", "d"]
=> ["a", "e", "b", "s", "d"]
irb(main):002:0> foo.collect {|c| c.upcase}
=> ["A", "E", "B", "S", "D"]


I prefer the high-order function approach (as opposed to manually iterating through the collection ) because I don't have to set any state, reducing the possibility of iteration-related bugs. The act of iteration over the collection and the creation of the new collection is the responsibility of the collection. My responsibility as a user of the collection is to say how to transform each element of the old collection into the element of the new collection.

Filter

There are a few different ways that you might want to filter a collection. You may want to only return elements where the predicate is true. This is done using the select method. The detect method is a special case of the select method where you're only interested in the first match. Lastly, the reject method only returns elements when the predicate is false.


irb(main):001:0> foo = ["a", "e", "b", "s", "d", "b"]
=> ["a", "e", "b", "s", "d", "b"]
irb(main):002:0> foo.select { |c| c == "b"}
=> ["b", "b"]
irb(main):003:0> foo.detect { |c| c == "b"}
=> "b"
irb(main):004:0> foo.reject { |c| c == "b"}
=> ["a", "e", "s", "d"]



Reduce

The Reduce pattern is useful when you want to return a scalar value from a collection. The high order function passed to the "Reduce" implementation requires an extra parameter, the accumulator. If this doesn't make sense, think about the example where you need to sum the area of various shapes. You need to have some value to accumulate the results into. And just like recursion requires a base case, Reduce needs to have a base value for the accumulator. This is the first argument to "inject"


irb(main):001:0> foo = ["a", "e", "b", "s", "d", "b"]
=> ["a", "e", "b", "s", "d", "b"]
irb(main):002:0> foo.inject("") {|acc, c| acc + c }
=> "aebsdb"



Notice that even though I have an accumulator variable, I'm not actually setting the accumulator to the new value, I'm just returning it. That's because my responsibility is only to provide the new value of the accumulator, the collection takes care of setting state.


Combining expressions

These abstractions are powerful on their own, but even more so when combined. Let's say you want to concatenate all of the lowercase letters of a collection together. First, you use the Filter pattern to remove all uppercase letters. After, you apply the Reduce pattern to aggregate the elements into one string.


irb(main):001:0> foo = ["a", "e", "B", "s", "D"]
=> ["a", "e", "B", "s", "D"]
irb(main):002:0> foo.select {|c| c == c.downcase}.inject("") {|acc,c| acc + c}
=> "aes"


Conclusion

High-order functions can be used to help separate orthogonal concerns. Map, Filter, and Reduce are responsible for iterating over the collection and collecting the results of the high-order function. These patterns are a great example of separating the abstract from the specific.

In my humble opinion, it's important to keep the high-order function free of side effects whenever possible. This removes the possibility of iteration-related bugs, which can be difficult to debug.

Saturday, February 2, 2008

Iconic Representation of Software

Many organizations purchase software development tools which allow their developers to create graphical representations of their business procedures. These representations are typically converted into source code for a target platform.

Colleagues of mine have often expressed frustration over the limitations this puts on the resulting code, especially when organizations try to mix custom code with generated. I tend to agree. Although, I've had a hard time describing precisely why I dislike it. Recently I've been reading "Toward a Theory of Instruction", which has given me a little more perspective.

In "Toward a Theory of Instruction", psychologist Jerome Bruner describes three stages of representation pupils use in problem-solving. Enactive representation is the most primitive representation, as it is action-based. The pupil progresses to image-based representation, called iconic representation. Lastly, the pupil represents problems using language, called symbolic representation. Students do not use only one representation at a time when learning new material; often, the student uses multiple modes until they are proficient with symbolic.


Given that context, I can see the appeal of modeling tools to non-developers; the iconic representation is relatively graspable. However, I've noticed quite a few disadvantages when the target language is Java. Frequently, the organization represents state using iconic, and process using symbolic. I'm not completely opposed to this methodology in theory, it sounds similar to Mr. Bruner's idea of mixed-modes of representation; but the consequences in implementation tend to be very complicated.

Java requires that each public class resides in its own file, and methods on that object can only reside in that file. Because the iconic representation will change over time, a developer cannot add custom Java code to the generated classes. This means that the symbolic representation is limited to the expressiveness of the iconic representation. As such, the resulting classes are not encapsulated state-processes. I've seen multiple attempts at alleviating this problem; creating a parallel class hierarchy to the generated classes, or sub-classing each generated class to add in the appropriate responsibility. Given the statically-typed nature of Java, I haven't found either to work effectively in practice.

While I generally don't like or use Microsoft's products, Microsoft's partial classes allow for a reasonable mix of iconic and symbolic representation. Partial classes allow methods for a class to reside in multiple files; state can be represented using iconic, and the symbolic custom code can reside in a separate file.


In an ideal world, everyone would have a decent understanding of symbolic representation. And I think Smalltalk does an excellent job at creating a symbolic representation that everyone, including children, can comprehend. But, as Paul Graham says in On Lisp, "An ideal world is left as an exercise to the reader."

Thursday, January 10, 2008

Java's interfaces

I've often heard people say that Java's interfaces are Java's way of avoiding multiple inheritance. I disagree.

I would argue that Java's interfaces are a Protocol-inspired workaround of _excessive_ static typing.

I personally need to read more about Haskell to expand my understanding of what static type systems have to offer.

Scheme's Continuations

I've been reading up a lot more on Scheme lately. Initially, one of the more confusing areas for me was continuations; but I'm starting to get a decent grasp of them.

Mr Dybig's scheme book was very nice, but I didn't quite follow his written explanations on continuations. So I'll try to explain them a little better. I'm really just writing this for my own understanding, so I'm omitting a lot of details from the book.

1)

(let ((x (call/cc (lambda (k) k))))
(x (lambda (ignore) "HEY!")))

x gets bound to the continuation, which is

(lambda (y) (let ((x y))
(x (lambda (ignore) "HEY!")))


So

(let ((x (call/cc (lambda (k) k))))
(x (lambda (ignore) "HEY!")))


is equivalent to
(let ((x (lambda (y) (let ((x y))
(x (lambda (ignore) "HEY!"))))))
(x (lambda (ignore) "HEY!")))

which is equivalent to

((lambda (ignore) "HEY!") (lambda (ignore) "HEY!"))



"HEY!"

2)
Equation:

(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!")


The continuation is:

(lambda (y) ((y (lambda (x) x)) "HEY!"))


So the expression expands to the following.

(((lambda (y) ((y (lambda (x) x)) "HEY!")) (lambda (x) x)) "HEY!")


It's important to note that as soon as the continuation is applied, the value is immediately returned.

That means that

(((lambda (y) ((y (lambda (x) x)) "HEY!")) (lambda (x) x)) "HEY!")


ie equivalent to

(((lambda (x) x) (lambda (x) x)) "HEY!")



((lambda (x) x) "HEY!")

"HEY!"