![]() |
Articles Feed |
Categories
Archives
- August 2010 (1)
- July 2010 (5)
- June 2010 (4)
- April 2010 (3)
- March 2010 (2)
- February 2010 (2)
- January 2010 (1)
- December 2009 (1)
- October 2009 (2)
- September 2009 (2)
- August 2009 (1)
- July 2009 (5)
- June 2009 (2)
- May 2009 (2)
- April 2009 (8)
- March 2009 (7)
- January 2009 (2)
- December 2008 (3)
- November 2008 (5)
- October 2008 (4)
- September 2008 (6)
- August 2008 (4)
- July 2008 (5)
- June 2008 (5)
- May 2008 (4)
- April 2008 (2)
- February 2008 (4)
- January 2008 (2)
- December 2007 (2)
- November 2007 (2)
- October 2007 (2)
- September 2007 (1)
- August 2007 (3)
- July 2007 (1)
- June 2007 (4)
- May 2007 (7)
- April 2007 (2)
- February 2007 (3)
- January 2007 (3)
- November 2006 (3)
- October 2006 (3)
- September 2006 (17)
- November 2004 (1)
Craftsman Swap at Relevance - Day 4
by: colin | July 9th, 2010 | 0 comments »
Today was my last day at Relevance, pairing again with Stuart Sierra. Along with Alan Dipert, we arrived at a solution for our data woes from yesterday, and deployed it. The approach we chose exposed a problem with data interpretation when a Clojure-precondition-thrown AssertionError came back to bite us later in the day. Note to self: AssertionError, which preconditions throw, is a java.lang.Error, not a java.lang.Exception. Catch it accordingly, especially if you're running these preconditions in a thread pool!
Today may have been the most fast-paced of my time here. In the morning after the project standup, Alan did some whiteboarding with Stuart and me to explain the architecture and requirements of a spike that we spent the rest of the day on. It's going to be a pretty cool system that integrates with the rest of the client system. The interesting bits include writing to Redis (potentially with a C application) and a web service (in Clojure) that reads from Redis server to provide data to end users.
So Stuart and I started from scratch on a new Compojure app with Clojure 1.2, Leiningen, and redis-clojure. We got set up relatively quickly, and implemented a tiny web service that parses a request to find what to read from Redis, does all the proper error handling, and returns a reasonable result. We had ideas about providing several types of web services (HTML, JSON, XML, perhaps even plain text), but for the purposes of the spike, we just used the browser.
I had fully expected Stuart's knowledge of Clojure to be impressive, and I wasn't disappointed. I didn't see too many things I hadn't seen before, but having seen things is different than knowing just when to use them. There was a new macro, condp, that I hadn't seen before, and it seems like a great substitute for cond in situations where all the predicates look very similar. And if you've ever been frustrated by needing to restart a Clojure process in order to add a jar to the classpath, you'll be excited to know that Stuart is working on an interesting solution involving Nailgun.
It's also been cool to hear a couple of questions Stuart Halloway asked us about Clojure idioms (he kindly included me in the questions, which were really for Stuart Sierra). It's sometimes easy to forget that everybody's human, and the smartest people will often ask for help rather than forge ahead as a lone warrior, and they're better off for it - even when it's just rubber ducking.
On that note, my experience here has been that almost everyone seems to be pairing all the time, and those who aren't pairing are either working on project management or QA-type tasks, or have their code reviewed by someone else later on. My own experience at 8th Light has always been that two heads are better than one, so this was cool to see. Additionally, as I've said before, the developers all seem to be very good at client-relations issues, and I discovered today that, as I suspected, Relevance uses its own developers as project managers for all projects. This seems very noteworthy to me - it's been rare that I've seen a developer as project manager, but it seems to be the rule here. This is also often the case for the QA role. Certainly there is a lot of testing going on here at both the unit and acceptance test level, but there is often a developer doing QA on other developers' work.
My experience this week was great. I would highly recommend anyone considering doing something like a craftsman swap / journeyman pairing tour to just do it. This has been a wonderful experience, and it's easy to see why people like Corey Haines have been such proponents of this sort of thing. Relevance would be an excellent choice for a visit if you can make it happen - I've learned a lot, and I look forward to bringing more of that back to the team at 8th Light when I get back to Chicagoland.
Many thanks to 8th Light and Relevance for the opportunity to do this!
Craftsman Swap at Relevance - Day 3
by: colin | July 8th, 2010 | 0 comments »
Day 3 at Relevance began, as the previous days, with the company standup. Stuart Sierra, of clojure.test and Practical Clojure fame, was my pair for the day. Yep, there are two Stuarts at Relevance with Clojure books! If you're interested in Clojure, and you haven't already purchased the Apress book, electronic or print, you should do that.
We started off with some Bash scripting for a cron job. Mostly pretty straightforward stuff, though I did really like the way the structure and logging behavior in the script turned out. I won't go so far as to say that this (or any) Bash script is a thing of beauty, but it's very clear, concise, and is going to do the job very well. One cool thing I hadn't realized was possible (and Stuart mentioned that a decent amount configuration is necessary for this) is that we used using sendmail to, well, send mail - but directly from the command line. So we had something along these lines:
message=`cat email_file_contents.txt` sendmail -t $message
Our needs weren't very complex with regard to things like email headers, so it really was dirt simple to use, which was a very pleasant surprise.
We worked in Emacs, which was a bit of a struggle for me, but a reminder that I ought to be able to get around a bit better in that editor, as I'm interested in Clojure and many people in the community are gung-ho about it. org-mode was one notable takeaway there - we used the tables there to structure our table-based tests, and it can do some pretty cool formatting. I'll also say in Emacs' favor that users and authors sure are serious about documentation (just look at the previous link or the GNU Emacs Manuals), which I love to see. However, it can be a bit intimidating when you feel like you have to read a few books to get to know the editor.
At the project standup with Stuart, Alan Dipert, and Shay Frendt, the client reported a problem with a story that's still in progress, so Stuart and I spent the remainder of the day chasing this bug. There were several bright spots, however: we added several higher-level tests around some data-translation layers of the system (which includes JRuby on Rails and Clojure applications). Our tests were on the Clojure side of things, which was great to get a chance to see. Stuart had this great idea to write table-based tests a la Cucumber or Fitnesse, and we wrote a quick and dirty parser for a syntax similar to Cucumber's, plumbed a few tests in, and found one of our problems after a bit of data correction. We found the other, more mysterious problem soon afterward, and spent most of the rest of the day trying to track down the exact reason for it. It's interesting that neither of these problems had much to do with code - they were both problems with data. In one case, we received data in a format we didn't expect, and in the other, a subset of data suddenly went missing. I generally feel like good practices like TDD and pair programming can save you from many unexpected errors, but I don't know that there's a good solution for cases where data is mucked up, besides deploying, seeing what real data looks like, and adapting based on those results. I would suggest something like Haskell's QuickCheck (and similar ideas elsewhere), to try out more possibilities in the tests, but even if we used something like that here, I have a feeling we would have still ended up with an incorrect constraint, so wouldn't have caught these problems.
These problems make me wonder if, as external data drives more and more of a given application, it becomes more and more important for the data itself to be tested. That is, it would be ideal to be able to write tests that make assertions against the structure and contents of the external data. I'm not sure whether that would have been possible in this case, due to privacy concerns, but it's an idea that I'd love to hear feedback on anyway. And now that I imagine such a test system more carefully, maybe that's just design by contract in a different light?
Looking forward to tomorrow!
Craftsman Swap at Relevance - Day 2
by: colin | July 7th, 2010 | 4 comments »
Today was my second at Relevance for our craftmanship swap (see my first post for the goods on Day 1). Chris and I continued work on the project from yesterday. I was glad to have a chance to continue the story work we'd started, and see it through to completion by this afternoon, eliminating a few timezone bugs along the way (I'll get back to that).
We started the morning off with the company-wide stand-up meeting again, followed by a retrospective for the project I was pairing on. Chris explained that every iteration on a given project, Relevance does either a retrospective or a risk assessment meeting. After some scheduling and telephone difficulties on the client's side were (mostly) sorted out, Jason kicked us off as the retrospective facilitator. I haven't been on a project that held retrospectives on a regular basis before (though we've certainly done them at times), so it was interesting to see the very structured approach Relevance takes. As a brief outline, the team (and customers) began by outlining their expectations and hopes for the retrospective, followed by ratings of how several areas of the project (communication, ROI, building the right thing, etc.) were going, and finally a review and a set of action items with due dates attached. The team members - Chris, Jason, Don Mullen, and Michael Parenteau - were all excellent at interacting with the customers. I like to think that I'm pretty good at that kind of interaction, but there's a lot I picked up in a short time on that conference call. I heard a lot of rephrasing the customer's concerns to verify that the team always had the correct interpretation, and I'm sure the customer came away feeling like their needs were really being addressed, especially with the clear action items to address any issues that came up. Michael's design work on this project, incidentally, is pretty killer and got rave reviews from both of the client representatives.
In yesterday's installment, I neglected to mention the project management tool the teams use, Mingle. It's a very nice tool, which looks to have a ton of features, but (unlike some other many-featured products I've used) manages to keep the interface very clean and simple. I'm not sure in what situations I'd feel compelled to switch to it over something nice (and free) like Pivotal Tracker or Agile Zen, but it is an impressive piece of software that I'm glad to have had a chance to take a look at.
So... time zones. Every time I deal with them it's a mind-bending struggle to keep all the concerns in their proper place, and today was no exception. We had our Time.zone in Rails set to UTC, but were still getting some EST times. Well, it turns out things like Date.today.beginning_of_day don't respect that setting and use whatever the default system time zone is. After about an hour of investigations and pondering, we eventually decided to replace most uses of Date with the Rails TimeWithZone object, allowing some mildly unsavory naming with the understanding that the decision is going to need to be revisited to account for various user time zones anyway. It seems to me that this is a universal problem for apps that might be used in different time zones. Chris suggested that this might add to the often-quoted-but-rarely-sourced list of hard problems in computer science: cache invalidation and naming* (and off-by-one errors?). So henceforth, time zones are in there too. That's right, you heard it here first: it's three (or four, depending on if you're telling the off-by-one joke) hard problems: cache invalidation, naming, and time zones.
After work Aaron Bedra, Alex Warr, Stuart Halloway, and Stuart Sierra introduced me to my first draft-style game of Magic the Gathering. Yes, that's right, I spent the evening with three of the Clojure/core guys and learned a ton... about Magic. It was fun - I got a TON of help from everybody, especially Alex, and with a lot of help, I actually won a few rounds. We played duels, best-of-3, and I went 2-2 overall in games. And by "I", I mostly mean "the people who told me what I should put down." I heard a rumor on one end of the table that Relevance prefers to hire Magic players over non-players as programmers**, so potential applicants should take note. I don't know that I'll run out and buy a deck, but it's always fun to learn a new game, especially when the cards are named things like "Lord of Shatterskull Pass".
Sounds like I'll be sitting in with Alan Dipert's team tomorrow on some Clojure work, which I'm very much looking forward to.
* Some people on the Internet say the credit belongs to Phil Karlton, so it must be true.
** This sounds made up, and may be.
[UPDATE: fixed retrospective timing description based on Jason's comments below]
Craftsman Swap at Relevance - Day 1
by: colin | July 7th, 2010 | 2 comments »
I'm both honored and humbled to represent 8th Light on the latest Craftsmanship Swap, with Relevance in Durham, NC. I'd first heard about Relevance through Stuart Halloway's excellent book Programming Clojure, and their reputation precedes them in the Clojure community, as well as in the Ruby/Rails world. Jason Rudolph had me come in a few minutes early this morning to give me a quick introduction to the company before their company-wide standup, where the whole company gathered and very efficiently went through the interesting goings-on of the day. The plan for now is for me to spend a couple days working in Ruby/Rails, and a couple on Clojure - I'm excited about both.
![]()
I paired up with Chris Redinger to work on a Rails project that's just a few weeks old, but already doing some pretty cool stuff. There's a pretty slick graphing library on the project called Highcharts, which apparently even works on IE6 (gasp!). We did some refactoring, which was a pleasure - Chris has a great eye (nose?) for code smells and writing excellent code (as well as customer relationships), and I often felt like we were on the same wavelength as we made improvements. We ran into a strange issue with the RSpec version we were on: models seem to be loaded twice during our spec runs, which gave us annoying errors about redefining constants (when we were most definitely only defining them once). It turned out the right place for the (non-ActiveRecord) models was actually under lib/ in this case, and that cleared up our problem. Chris thought this may have already been fixed in the latest RSpec 2 beta, but unfortunately we can't upgrade because newer versions are only compatible with Rails 3, which we're not using on this project.
We also got some feature work done, of course. The code is a pleasure to work in - clean, plenty of tests, and several Thundercats references, which is perhaps most important of all. In all seriousness, it was pretty easy to jump in and contribute, and that's been due in large part to the high quality of the code. Bundler, by the way, seems awesome. I've heard mixed reviews, but my experience installing gems today was such a breeze that I'm definitely going to try to use it on my next Rails project. I also sometimes forget how freeing it is to work on a project using Git - all of our greenfield projects use it, but I've gotten used to being on Subversion projects, where making a branch is a big production. Chris uses feature branches regularly, and they seem to work pretty well.
The environment at Relevance is really nice - a big open space with lots of pairing stations, drinks and snacks, and even a keg of Aaron Bedra's delicious home-brewed Belgian-style wheat beer on tap. We had a great lunch of Thai food and very techy conversation - Node.js, Clojure, and EventMachine all got some playing time, and everyone agreed that Aquamacs was very pretty. Wait, maybe that last part went differently... After work, Aaron, his fiancee, Stuart Sierra, Jared Pace and I grabbed some Mexican food (after what was apparently a second failed attempt to eat at a place that serves something called a "Defibralator" - don't blame me, that's how they spell it on the online menu).
Chris and I ended the day working on tracking down a data issue, which we hadn't completely solved by the end of the day, but we narrowed the possible culprits down significantly, and I'm sure it'll be obvious to us in the morning. Looking forward to tomorrow's adventures!
JavaScriptness.prototype = new Class(); From Classical to Prototypal
by: justin | July 6th, 2010 | 0 comments »
It has gotten a bad rap because most people that use it don't look for its brighter side. Instead they will often look online for some code to copy paste, or they will hack something together using tiny snippets and in-lines to get a drop down menu.
It is also a very conflicted language. By nature, JavaScript is a Prototypal language where nearly everything is an Object and there are no classes. It is also somewhat Functional since all the functions are First Class Functions. They are just more objects that can be passed into and returned from other functions.
The Classical Form
Lets take a look at a basic Classical implementation of a Square using JavaScript:function Square (side) { this.side = side; } Square.prototype.area = function () { return this.side * this.side; }; Square.prototype.perimeter = function () { return this.side * 4; }; var mySquare = new Square (5);You will notice that JavaScript even has a new key word in an attempt to match a Classical implementation. The function Square () defines a class with a side attribute. It also has two instance methods, area and perimeter. We can then create mySquare in almost the same way we might do it in Java. This is JavaScript though, and the new works differently in JS. It creates a new, empty object and then calls the Square() function (or the constructor) passing the empty object into this . The constructor then populates that object with the specified behavior before returning it. This is particularly scary, because if you forget to put new in front of the constructor, this will refer to the Global Object, as will mySquare (meaning any further changes made to mySquare would also be on the Square 'class'). This is why, if you want to use JS in the Classical way, you should always capitalize the first letter of a constructor.
Ok, so we have our Square, but say we want to create a square that holds a X or an O. Well, we would want to inherit the properties of our current Square 'Class' and then add to them. We might do something like this:
function ContainerSquare (side, contents) { this.superclass(side); this.contents = contents; } ContainerSquare.prototype = new Square(); ContainerSquare.prototype.superclass = Square; ContainerSquare.prototype.constructor = ContainerSquare; ContainerSquare.prototype.getContents = function () { return this.contents; }; var myContainer = new ContainerSquare(6, "X");We create a new 'Class' for the ContainerSquare which uses the Square's constructor to define the side attribute, along with the two instance methods. We then define our new contents attribute, along with an accessor method to go with it.
The ContainerSquare .prototype = new Square(); line sets up a Prototypal inheritance structure so that a ContainerSquare object will be linked to the proper prototype chain.
The prototype chain is the hierarchy of objects that a method or attribute call will traverse until it finds what it is looking for. In other words, when I call myContainer.size(), JavaScript will first check to see if the myContainer object has that function. If not, it will proceed to check the object's prototype, which is the ContainerSquare. Since ContainerSquare doesn't have the function, next in line is ContainerSquare's prototype, which is just Square. Square does in fact have a size() function, and since javascript will use the first function it finds, it will use Square's size() function.
Thus, by setting ContainerSquare's prototype to Square, we inherit any of the attributes or methods of Square.
Although this all works, and we have successfully mashed a Prototypal language into a Classical scheme, we should try this in the way JavaScript wants to be used.
The Prototypal Form
We can start with the Square. There are few pretty simple ways to achieve the same functionality using regular objects and their prototypes, and we will look at two of them. The first will create a square object that we can use. Then if we need more squares, we can make a copy of that object using its prototype. The second will create a squareMaker function, which can then be used to pop out new squares.var firstSquare = { side: 5, area: function () { return this.side * this.side; }, perimeter: function () { return this.side * 4; } };Here, we already have a new and usable square at our disposal. We don't need to call a constructor and define any types. We can just take an object and mold it into the form we want.
Say we want another square though. We can't just write something like var secondSquare = firstSquare; because JS passes objects by reference, and thus the second square would just point to the first square. What we can do, and this is a technique developed by Douglas Crockford, is make a copy of our object by calling a new constructor with a prototype that points to our object. This new contructor creates a new empty object and assigns the values of our old object to the new empty object. You can do this yourself, or you can use Crockford's technique as follows:
if (typeof Object.beget !== 'function') { Object.beget = function (o) { var F = function () {}; F.prototype = o; return new F(); } } var secondSquare = Object.beget(firstSquare); secondSquare.side = 6;You can see that we are actually defining an on the fly constructor F, using our object 'o' to define F's prototype (where 'o' is firstSquare). Then we create a new object using that constructor. This will give us a new copy of our object, with all its attributes and functions. If we now called secondSquare.area(); we would get 36.
If you wanted to then make a ContainerSquare, you could simply add a contents attribute to the second square, and then make copies of the secondSquare if you need more Containers. Keep in mind that since firstSquare is the prototype of secondSquare, if you were to add a contents attribute to firstSquare, you would then have that attribute on secondSquare; however, adding attributes to the secondSquare does not place them on the firstSquare.
Spawn More Protolords
The other way to get squares would be to make a squareMaker function. This function will return a new object with whatever attributes you define. I am also going to show you some closure so that the attributes are private, and only accessible through accessor methods.var squareMaker = function(side) { return { getSide: function() { return side; }, area: function () { return side * side; }, perimeter: function () { return side * 4; } }; }; var anotherSquare = squareMaker(5);You will notice that the return value of the squareMaker is almost exactly like how we defined our firstSquare object. We are just returning the definition of a square, and thats quite awesome. Another thing you will notice is the bit of closure. We pass a value into the squareMaker, but it isn't stored anywhere. It is held in the scope of the squareMaker function, allowing those internal methods to use it, but hiding it from the outside (unlike the side attribute defined in the firstSquare). This sort of closure is another wicked awesome tool you can use in JS. In a way, this use of closure is like defining private variables to a class.
To get the Container functionality we create a containerMaker using the squareMaker, and some more closure, to make a new square object. We then dynamically add a getContents method to provide access to our private contents attribute.
var containerMaker = function(side, contents) { var container = squareMaker(side); container.getContents = function () { return contents; }; return container; }; var anotherContainer = containerMaker(6, "O");
Conclusion
So we have now seen two ways to use some of the better parts of JavaScript to get the same functionality that we could get using the Classical scheme. We can also see some advantages in using JS in its natural form like: getting some closure (which can be exceedingly powerful), very dynamic objects ready to change in anyway you can think of, quickly defined objects which can be used and multiplied, and no need to predefine types. Pretty sweet right?I will admit one slight inefficiency with the two solutions I showed you (although there are ways around this). Using the squareMaker, or making copies of the objects will make full copies, including the function objects defined inside. If you use the Classical scheme I showed, you are defining functions on the prototype rather than the object itself, thus there will only be one copy of the function. You can, of course, do something similar in the JS scheme, but the optimization doesn't count for all that much in most cases (unless you are doing mobile development where you want to save everything you can!).
JavaScript isn't a Classical language, but instead a Prototypal language that is powerful enough to mimic a Classical language without breaking a sweat. There is much to be gained by recognizing this fact and changing your mindset to work with it. Trying to fit a square into a circular hole will just get you stuck. All languages are unique with a variety of their own advantages, and as good developers we should recognize these differences and reap all the benefits they have to offer. #
