Things I Have Learned Recently About Development
This is a post from Luke's old blog; it is saved here statically for historical purposes, as of October 2008
This is the second post in the series Things I Have Learned Recently
Development
I'd say there are three big things I've learned recently about coding:
Testing
In terms of tools, I've started using RSpec instead of test/unit, but what really matters is that I think about testing much differently now. I don't know that I'm testing "well" yet, but I'm at least testing much, much better. In particular, I'm doing my best to focus on the behaviour of the code that I'm testing, rather than internal state or unexposed behaviour, and I'm using a lot more mocking and stubbing to avoid setup/teardown costs and force simplification of interfaces. I'm also writing much shorter tests although many more of them.
A lot of my older tests were classes with a few, very long tests, each of which exercised a specific aspect of the given class's functionality. Newer tests, though, will treat that functionality as a context, which will itself have many specific behaviours, and each of those behaviours will get its own test.
I think I'm still making some mistakes here, as my contexts are generally per-method, which I think is a mistake. For instance, I have a Collector class whose tests I recently decided to rewrite. This class can be used to find either virtual or exported resources, and it can be used with either a query or by specifying individual resources. These are really the main contexts I should be testing, but I didn't really do that. One of the issues is tha RSpec itself doesn't do much to make this easier, but it's not really fair to blame the tools.
Design
Amazingly, Puppet hasn't had a class to model configurations until recently, nor has it had classes to model nodes or the different aspects of file serving. It's recently been made clear to me how important it is that I draw classes out of my code, and it's had a huge impact on clarity and maintainability. It's tough to describe exactly what I mean here or how to find these classes that aren't yet classes.
The main reason Puppet never had a Configuration class is because configurations show up in so many forms -- at the least, they exist during compilation, transfer, and execution. To see them as a common class, I had to step up a bit, and I'm still not entirely satisfied wih the abstraction, but man, it's a lot better than it was.
The biggest change is that we're moving to REST from XMLRPC, and REST enforces a standardization that is entirely absent from my shoddy XMLRPC implementation. REST only has a few verbs (methods) -- find, destroy, and save, mostly -- whereas with XMLRPC I can make as many verbs as I want. This limitation enforces a consistency across all of my network-enabled classes, and at the same time requires that me expose those classes that maybe I didn't see clearly before. In order to find a Node, you must first have a Node class to call find on, for instance.
Where previously I had ten different classes, each with a unique set of methods that worked over the network and each of which didn't clearly model anything explicitly -- because they were more focused on providing network transparency than on classes or objects -- I now have a roughly equivalent number of classes but each modeling specific objects that I want to pass around the network.
Development Process
First of all, distributed development is awesome. I kinda regret choosing git, because its usability is as bad as everyone says, but it really has made it easier for people to contribute patches and code. Its in-repository branching has made it much easier for others to create and publish their own branches and then for me to integrate their work. I don't know that I have any more people contributing, but the contributions seem more meaningful.
Mainly, though, I've learned that feature branches really are a good idea. I tried them about a year ago but I found them to be just overhead, given how few people were participating and how short my development cycles were. Recently, though, I've been doing larger chunks of work and there have been more people involved, so feature branches make much more sense. In particular, I haven't had a clean master branch in a while because I've been doing all of this development in it, but at the same many bugs have been getting filed and fixed. I couldn't release because of the lack of cleanliness of the main branch, all because I wasn't using feature branches.
Conclusion
Mainly, it's clear that I still don't really know what I'm doing. I like to think I've become a much better developer in the last three months, but it's been three months of little apparent progress from the outside and a lot of pain and frustration on my part, so it's hard to see the positive right now. Hopefully we'll all reap the benefits in the near future.
Check back tomorrow for a post on managing open source projects.