Thursday, October 29, 2009

A response to "Failures in Isolation"

Following Corey Haines on twitter is such a good idea. Today he dropped this gem:

Please read, I'm not going to paraphrase it. Nevermind, I will. But it will be really short. Poorly designed code that is tested with a high level of isolation causes a problem. You can't refactor it with confidence because the tests, or the mocks, are blocking your progress. So let's talk about how they impede refactoring first.

Tests prevent behavior from flowing 'up'. For instance, if you mistakenly coupled a model class to a view tier class you could not 'refactor' this problem without breaking the tests for your model. Most likely, the test will fail because the API of the class has changed, you no longer pass the request.

For Mocks it is the opposite. You cannot move behavior 'down'. Let's say I have leaked some model behavior into my controller and I wish to move it to the appropriate model. If my test uses the real model, not a mock, this is not a problem. I can move the behavior and my controller test will still pass. Now I can safely write model tests for the new behavior and delete the controller test that now duplicates it.

If I have mocked the model, however, my controller test will fail when I attempt to move the behavior 'down' into the model. One offense is not an issue. I was involved in one system where an entire test suite was thrown away because of improperly used mocks. Death by a thousand paper cuts.

I have no universal solution for this problem - as it is a problem of my skill as a designer and the skill of my peers. However, I have come up with two helpful guidelines.

Only directly test code you like

I dislike code when I'm unsure of its design. I also dislike code that appears volatile. As my confidence has grown I find myself more comfortable with my early design decisions and more willing to glorify my creations with their own test sooner. When I am not confident I keep my tests at a high enough level where I can refactor freely. As my confidence grows in a system I move towards higher levels of isolation.

Only mock code you like

For all the same reasons as above. Mocks crystalize an API for a class and can cause a lot of problems if the class is used often in a system and the class it is poorly designed. As the ugliness and volatility of code increase, mock it less.

In Conclusion

As with everything, the value of isolation in testing is not an absolute. For younger developers I suggest beginning with a state-based testing approach over using mocks pervasively. A state-based style will afford you maximum flexibility to refactor your design. As your experience grows begin to use mocks to solve some of the problems that state-based testing will invariably bring about.

That is the path I travelled and it worked out alright for me.

Friday, August 7, 2009

A log4j adapter for Rails

This current client application I'm working on is a mixed bag of Ruby and Java parts. All our existing logging for the older Java parts uses log4j and we wanted to unify our Rails logging with that. I spent a couple of hours putting together this adapter we now use. If you need something similar it should give you a good place to start.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Log4jAdapter
include ActiveSupport::BufferedLogger::Severity
L4JLevel = org.apache.log4j.Level

SEVERETIES = {
DEBUG => L4JLevel::DEBUG,
INFO => L4JLevel::INFO,
WARN => L4JLevel::WARN,
ERROR => L4JLevel::ERROR,
FATAL => L4JLevel::FATAL,
}
INVERSE = SEVERETIES.invert

def initialize
@logger = org.apache.log4j.Logger.getLogger('com.shc.mmh.Rails')
@root = org.apache.log4j.Logger.getRootLogger
end

def add(severity, message = nil, progname = nil, &block)
message = (message || (block && block.call) || progname).to_s
@logger.log(SEVERETIES[severity], message)
end

def level
INVERSE[@logger.getEffectiveLevel]
end

def level=(level)
raise "Invalid log level" unless SEVERETIES[level.to_i]
@root.setLevel(SEVERETIES[level.to_i])
end

def enabled_for?(severity)
@logger.isEnabledFor(SEVERETIES[severity])
end

#Lifted from BufferedLogger
for severity in ActiveSupport::BufferedLogger::Severity.constants
class_eval <<-EOT, __FILE__, __LINE__
def
#{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
add(
#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
end # end
#
def
#{severity.downcase}? # def debug?
enabled_for?(
#{severity}) # DEBUG >= @level
end # end

EOT

end

def method_missing(meth, *args)
puts "UNSUPPORTED METHOD CALLED: #{meth}"
end
end

Wednesday, August 5, 2009

A Scala version of Unle Bob's lazy PI sequence in Clojure

I follow Uncle Bob on twitter and I'm also currently learning Scala. When I saw his tweet about a lazily evaluated infinite PI sequence in Clojure I couldn't resist giving it a shot in Scala. Here's my result (it works!). Feedback is absolutely welcome.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//Gives us the :: syntax for streams.  From http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient.
class RichStream[A](str: =>Stream[A]) {
def ::(hd: A) = Stream.cons(hd, str)
}
implicit def streamToRichStream[A](str: =>Stream[A]) = new RichStream(str)

object M { //Gives us a shorthand for declaring BigDecimals that Scala lacks
def apply(i:Int) = BigDecimal(i)
}

//Hack to work around poor bigdecimal support
val mc = new java.math.MathContext(300,java.math.RoundingMode.HALF_UP)
def divide(a:BigDecimal, b:BigDecimal) = {
new BigDecimal(a.bigDecimal.divide(b.bigDecimal, mc))
}

def piSummands(n: BigDecimal): Stream[BigDecimal] = {
divide(M(1), n) :: piSummands(n + M(2)).map(_ * -1)
}

def scaleStream(stream:Stream[BigDecimal], factor:Int) = {
stream map {_ * factor}
}

def addStreams(s1:Stream[BigDecimal], s2:Stream[BigDecimal]) = {
s1 zip(s2) map {z => z._1 + z._2}
}

def partialSums(s:Stream[BigDecimal]):Stream[BigDecimal] = {
s.head :: addStreams(s.tail, partialSums(s))
}

def piStream = scaleStream(partialSums(piSummands(1)), 4)

def square(s:BigDecimal) = s * s

def eulerTransform(s:Stream[BigDecimal]):Stream[BigDecimal] = {
val s0 = s(0)
val s1 = s(1)
val s2 = s(2)
val head = s2 - divide((square(s2 - s1)), ((s0 + (M(-2) * s1) + s2)))
head :: eulerTransform(s.tail)
}

type Transform = (Stream[BigDecimal]) => Stream[BigDecimal]

def makeTableau(transform: Transform, s:Stream[BigDecimal]):Stream[Stream[BigDecimal]] = {
s :: makeTableau(transform, transform(s))
}

def acceleratedSequence(transform:Transform, s:Stream[BigDecimal]) = {
makeTableau(transform, s) map {_.head}
}

val set = acceleratedSequence(eulerTransform, piStream)
println(set.take(150).last)

Monday, August 3, 2009

Rails threadsafe! and Engines

If you're planning to use the combination of engines and threadsafe! you'll need to do some extra work. Due to a bug in Rails the engine load paths are not added to the eager_load_paths at startup time. This makes engines unavailable in threadsafe! mode.

Fortunately, working around this problem is simple. Just subclass the plugin loader like this:



1
2
3
4
5
6
7
8
class EagerLoader < Rails::Plugin::Loader
def add_plugin_load_paths
super
engines.each do |engine|
configuration.eager_load_paths += engine.load_paths
end
end
end

And wire up your new loader in your environment.rb:



1
2
3
4
5
6
7
8
9
#require the plugin loader
require File.join(File.dirname(__FILE__), '..', 'lib', 'eager_loader')

Rails::Initializer.run do |config|
#override the default loader
config.plugin_loader = EagerLoader

# ...
end

Thursday, June 25, 2009

Big O for all you fellows who slept through the algorithms course

http://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/

Tuesday, May 5, 2009

Mathematicians should never code alone.

Case in point:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (xGrad * yGrad <= (float) 0 /*(1)*/
? Math.abs(xGrad) >= Math.abs(yGrad) /*(2)*/
? (tmp = Math.abs(xGrad * gradMag)) >= Math.abs(yGrad * neMag - (xGrad + yGrad) * eMag) /*(3)*/
&& tmp > Math.abs(yGrad * swMag - (xGrad + yGrad) * wMag) /*(4)*/
: (tmp = Math.abs(yGrad * gradMag)) >= Math.abs(xGrad * neMag - (yGrad + xGrad) * nMag) /*(3)*/
&& tmp > Math.abs(xGrad * swMag - (yGrad + xGrad) * sMag) /*(4)*/
: Math.abs(xGrad) >= Math.abs(yGrad) /*(2)*/
? (tmp = Math.abs(xGrad * gradMag)) >= Math.abs(yGrad * seMag + (xGrad - yGrad) * eMag) /*(3)*/
&& tmp > Math.abs(yGrad * nwMag + (xGrad - yGrad) * wMag) /*(4)*/
: (tmp = Math.abs(yGrad * gradMag)) >= Math.abs(xGrad * seMag + (yGrad - xGrad) * sMag) /*(3)*/
&& tmp > Math.abs(xGrad * nwMag + (yGrad - xGrad) * nMag) /*(4)*/
) {
magnitude[index] = gradMag >= MAGNITUDE_LIMIT ? MAGNITUDE_MAX : (int) (MAGNITUDE_SCALE * gradMag);
//NOTE: The orientation of the edge is not employed by this
//implementation. It is a simple matter to compute it at
//this point as: Math.atan2(yGrad, xGrad);
} else {
magnitude[index] = 0;
}

Thursday, April 30, 2009

Ruby's object.methods reflection in Scala

Update: Just found out the Scala REPL in trunk has tab completion, which does pretty much exactly this with a lot less fuss. Cool.

If you're coming from the Ruby world to learn Scala you'll learn quickly how much you miss Ruby's elegant reflection. On day 5 of my Scala adventure I took a crack at using Java's reflection APIs to do the job. I think it worked out pretty well. I'd love to hear what you think about it.

get the code here



1
2
3
4
5
//names of all methods, including super classes
namesOf(methods("Foo"))

//signatures of all methods, excluding super classes
signaturesOf(declaredMethods("Foo"))