Rails Migrations and Subversion 3
In rails, migrations are generated like so
paul-pagels-computer:~/RailsProjects/project paulpagel$ ruby script/generate migration CreatePacketTimestamp exists db/migrate create db/migrate/013createpacket_timestamp.rb
This creates a numbered migration with an up and a down schema direction. This has been incredibly helpful when dealing with the schema changes. The problem our team has found is doing migrations with subversion.
You run migrations by
paul-pagels-computer:~/RailsProjects/project paulpagel$ rake migrate
Which looks in the schema_info table to find which version of the schema your database is representing, and updates it to the most recent version (the highest number).
The problem comes into play when you have multiple people making migration scripts on their local machine at the same time. If two different people did a migration at the same time and committed them you would end up with two migrations. Which one gets run?
I am not sure how to solve this one yet. I have been loving rails, but this has already has put a dampener on it.
Ruby and Human Compilers
In Paul Graham’s Book, Hackers and Painters, he talks about patterns and Human Compilers. I started to think about how some traditional Object-Oriented patterns are implemented in different languages. What problems do these patterns solve?
Paul Graham’s human compiler is an interesting concept I would like to explore more with relation to ruby, which is what I have been working in lately. The object-oriented design patterns I have been taught are intended for one reason, to increase productivity. These patterns produce well decoupled, easily testable, clean, and reused code that makes it easier for developers to extend and maintain an application. It is the mind of the developer that produces this compiler to be able to read and interpret these patterns to perform workflow optimizations. When I see a pattern in the code, I can easily navigate the implementation and the problem that it is solving. I can hold the entire context in my mind to work on that piece of code. This human compiler is what allows me to move quickly through an unfamiliar piece of code. Moving to dynamic languages, I see the context I need shrinking in the traditional way, holding onto patterns. So I started to wonder, could we build patterns into the language better, or eliminate the need for them? Are the GOF patterns mostly just a method of satisfying our human compiler for statically typed languages?
I have suspicions that moving to ruby from C++/C#/Java will eliminate the need for many of the design patterns we have coveted in those languages. I would like to explore a few of them to prove this thesis. I want to look at the patterns that have helped make testing/design/decoupling better and see how they are different in ruby. Also, how can we transfer the values behind those patterns? The patterns were all based on good decisions, and can we learn anything from them or should we throw away the thought process that made them necessary?
Lets start by taking the most commonly used pattern, Abstract Server. Writing in C#, I need to create interfaces to make sure I don’t violate the Interface –Segregation Principle and depend on concrete classes. This becomes a big deal in a statically typed language because you don’t want to have to depend on a specific type. However, in ruby, you respond to messages of a class, which don’t care what type the return values are. Also, because it is a compiled language, you don’t want to have to recompile the clients of a class just because the implementation changes. In fact, in ruby, the Interface-Segregation violation goes away since there is no need for explicit interfaces to abstract, rather every class becomes an interface for itself.
Have you ever been working on a java/C++/ C# project and noticed an inheritance hierarchy that makes you twinge? Statically typed languages abuse inheritance by definition. Why do you need interfaces? Shouldn’t an abstraction be one of behavior? In ruby, you send messages to objects, which is the same type of firewall, as each object acts as its own interface. However, since an inheritance tree got there, you need to decouple it since it is growing large and not maintainable. Or have you seen interfaces placed in front of a class for the sole value of abstraction. A good example of this I have seen is with Views in the Model/View/Presenter pattern. Something that looked like this:
public interface ISomeView
{}public class SomeView : ISomeView
{//some implementation}
This uses the philosophy that the Views need to be decoupled from the Presenters. This is true, but the point of decoupled is missed. Decoupling is a method of using firewalls to hide the implementation of code from its clients (Abstract Server). How does this degenerate do this? It doesn’t. I have seen projects where inheritance is used liberally and there are interfaces for everything. I have also seen projects where inheritance is used conservatively and composition is used for everything, to prevent the formation of highly coupled inheritance trees. Finding the proper balance in static languages is difficult, but it is also a problem that should not exist. In ruby, inheritance is used on a YAGNI basis, as you only use it in the clearest of cases. It makes inheritance a tool to be used rather than monitored for abuses.
In ruby, you only inherit through necessity of behavior rather than clarity for form. Inheritance in most static languages is used as a tool for design patterns to make the code easier to read/work on/maintain for the developers. This is unnecessary in ruby since it is built into the language. Ruby does it instead of your human compiler. Writing beautiful code in java meant making the code clean and decoupled. Inheritance is no longer needed to do that in ruby, as it only serves a utilitarian purpose. Form is just as important in ruby as it is in static languages, it is just expressed without using features meant to serve efficiency purposes.
Self Shunt 2
The self-shunt method of testing has been conflicting for me. Self-shunt is a good testing pattern to test observers/views. A colleague of mine has started to convince me that self-shunt has some serious drawbacks. I want to explore the different ways to address the same pattern and how they fit into the test process and the test content. Are certain patterns easier to write and certain ones have a better final form?
Lets look at some code from Michael Feathers self shunt paper (see bottom for link). I extended it to do the mocking examples. The user story we are working with is the name of an item must be displayed on the led when the item is scanned.
Writing all of the tests did not require a concrete window (Display). We didn’t need to create the stub of the file to use; we could just use the interface. All the test patterns let the test be isolated in the test class/interface/production class triad. As a developer, it is easier for me to produce faster without quality loss if my context of thought is limited as much to the scope of the test as possible. Each extra window I switch is more contexts to deal with.
Here are three different tests:
public class ScannerTest extends TestCase implements Display
{
private Item lastItem;
public void testScan()
{
Item item = new Item("corn flakes");
Scanner scanner = new Scanner(this);
scanner.scan(item);
assertEquals(item,lastItem);
}
public void displayItem(Item item)
{
lastItem = item;
}
}The first test is making user of self-shunt test. Self-shunt was a quick way to start writing a test. The implementation on the interface in the test class will give you a good idea on what the implementation of the concrete class should look like when you get there. Also, the test is simple and the syntax is expressive. However, the scalability is questionable. If you had more than one self-shunted interface in a single test file, it would be hard to start differentiating between which variables are used in which. Also, moving around the file to get a good sense of what a test is doing is misdirectional and distracting. Ideally, I want to see the entire test on one screen, so I can read it. If there were many implemented methods in a test file that were not tests or helpers, there is the potential to be confused.
public class ScannerTest extends TestCase
{
public void testScan()
{
Item item = new Item("corn flakes");
Display mockDisplay = new MockDisplay();
Scanner scanner = new Scanner(mockDisplay);
scanner.scan(item);
assertEquals(item,((MockDisplay)mockDisplay).lastItem);
}
}
public class MockDisplay implements Display
{
public Item lastItem;
public void displayItem(Item item)
{
lastItem = item;
}
}Then I wrote the hand mock test. This test got rid of the clutter of implementing interfaces in the test and having local variables. Also, there are no external libraries needed, like a dynamic mocking library. The test is simple and easy to read. The biggest drawback is dealing with the hand mock test file. It is untested code that I have seen a tendency for behavior to slip into, which is disastrous. It can cause a bug in your tests that take too long to track down. Ideally this doesn’t happen, but I have seen it many times.
public class ScannerTest extends TestCase
{
public void testScan()
{
MockControl control = MockControl.createControl(Display.class);
Display mockDisplay = (Display) control.getMock();
Item item = new Item("");
mockDisplay.displayItem(item);
control.replay();
Scanner scanner = new Scanner(mockDisplay);
scanner.scan(item);
control.verify();
}
}Finally the dynamic mock test was written. This test was the simplest to write as a matter of process also the fewest lines of code. I never needed to leave the scope of the test function. It was just setting up my expectations and letting the test run. As Micah Martin pointed out to me, the test execution seems backwards and unreadable with dynamic mocks. The verification statements are at the beginning of the method and the execution is at the end. This is different than all the other tests in the system that follows an intuitive flow cycle of build, operate, and check.
With a little investigation I found Michael Feathers paper on Self Shunt (www.objectmentor.com/resources/articles/SelfShunPtrn.pdf).