Monday, April 09, 2012

Eval a Clojure Snippet in Java

The vast majority of the existing code for my current project is in Java, but the majority of the new code that we write is in Clojure; as a result, I spend quite a bit of time bouncing between Clojure & Java. Recently I was working with some Clojure code that was easily testable (in isolation) within Clojure, but was also executed as part of some higher-level Java integration tests. Within the Clojure tests I used with-redefs to temporarily set the state of a few atoms I cared about; however, setting the same state within the higher-level Java tests turned out to be a bit more of an interesting task.

Our Java integration tests, like all integration tests I've ever run into, look simple enough when looking at the code of the test; however, if you want to understand how the simple test exercises several collaborations you'll need to dig deep into the bowels of the integration test helpers. Integration test helpers are usually a very fragile combination of classes that stub behavior, classes with preloaded fake datasets, and classes that provide event triggering hooks. In my experience you also generally need the High-Level Test Whisperer on hand to answer any questions, and you generally don't want to make any changes without asking for the HLTW's assistance.

Today's experience went exactly as I expect all of my experiences with the functional tests to go:

I added a bit of behavior, and tested everything that I thought was worth testing. With all the new tests passing, I ran the entire suite - 85 errors. The nice thing about errors in functional tests: they generally cause all of the functional tests to break in an area of code that you know you weren't working in. I wasn't that surprised that so many tests had broken, I was adding a bit of code into a core area of our application. However, I wasn't really interested in testing my new behavior via the functional tests, so I quickly looked for the easiest thing I could do to make the functional tests unaware of my change. The solution was simple enough, conceptually, the new code only ran if specific values were set within the atom in my new namespace; therefore, all I needed to do was clear that atom before the functional tests were executed.

Calling Clojure from Java is easy, so I set out to grab the atom from the Clojure and swap! + dissoc the values I cared about. Getting the atom in Java was simple enough, and clojure.lang.Atom has a swap() method, but it takes an IFn. I spent a few minutes looking at passing in a IFn that dissoc'd correctly for me; however, when nothing was painfully obvious I took a step back and considered an easier solution: eval.

As I previously mentioned, this is not only test code, but it's test code that I already expect to take a bit longer to run**. Given that context, eval seemed like an easy choice for solving my issue. The following code isn't pretty, but it got done exactly what I was looking for.
RT.var("clojure.core", "eval").invoke(
  RT.var("clojure.core","read-string").invoke("(swap! my-ns/my-atom dissoc :a-key)"));
I wasn't done yet, as I still needed the HLTW's help on getting everything to play nice together; however, that little Clojure snippet got me 90% of what I needed to get my behavior out of the way of the existing functional tests. I wouldn't recommend doing something like that in prod, but for what I needed it worked perfectly.

** let's not get carried away, the entire suite still runs in 20 secs. That's not crazy fast, but I'm satisfied for now.

Sunday, March 04, 2012

When to Break Apart your Application

At speakerconf Aruba 2012, Stefan Tilkov presented on the topic of building Systems. One aspect of his presentation that really struck a chord with me was around the competing desires while designing and delivering an application. This blog entry is about summarizing that aspect and what I took away from it.**

Stefan noted that early in an application's life, a monolithic application is far easier to deliver; however, as the application grows, what is important begins to change. The slide to the right shows how priorities can change over time.

While starting with a monolithic application is easier to deliver, that application often grows to an unmaintainable size - i.e. the vast majority of the time we boil the frog. Stefan argued that the benefits are so obviously there that for an application of any moderate size it's more efficient to bite the bullet and break things up (where logical) in the beginning.

I'm guessing the vast majority of the applications that Stefan and innoQ encounter probably began knowing that they would grow to significant size and would have benefited from any type of modularization, but my working environment is a bit different. When I start something new for a trader at DRW -
  • the project may never grow to the unmaintainable size
  • if it does, it's likely that I'll want things broken up in a way that I couldn't have anticipated when the project began.
Given my context, I couldn't conclude that things should be broken up immediately, but I didn't want to ignore the point that Stefan was making about goals changing over time.

Stefan also had a slide about Modularization (also on the right) that gave numbers and recommendations on how to break things up. This slide reminded me of Matt Deiters' presentation at speakerconf Rome 2011. Matt told us about his experience teaching kids in Africa to program. While teaching programming, Matt observed that giving the children the single rule that they shouldn't have methods longer than 10 lines resulted in the children writing code with SRP, encapsulation, and other positive attributes. Matt argued that beginning with a simple rule that could get you 80% of what you want is likely better than 10 rules that, if followed correctly, could get you 100% of what you want.

I applied Matt's idea to Stefan's talk and suggested that perhaps the easiest thing was to take Stefan's modularization table and strictly adhere to changing things when LOC thresholds are broken. This would allow you to quickly deliver a monolithic application early in the development process, while avoiding boiling the frog in the future - once you cross the agreed upon magic number (LoC) then you aggressively address breaking the application into smaller and independent modules/processes/components/projects/whatever.

This strategy gives a nod to the fact that priorities do change as an application evolves and it's best to evolve the application along with those priorities, but not when it's too late. I plan to try this on my next greenfield application.

** I'm going from memory, so I could be slightly off. Don't hold Stefan accountable for my interpretation of his ideas.

Tuesday, February 28, 2012

Aligning Business & Programmer Goals

A theme emerged, last week at speakerconf, around the idea that programmers and businesses still don't seem to be on the same page. I'm not sure if it came up even earlier, but for me it began after I gave a presentation on Lessons Learned Adopting Clojure. The talk is similar to Lessons Learned while Introducing a New Programming Language, but focuses more on the technical aspects of selecting Clojure. Upon talk completion the first question I got was from Brian Goetz, something along the lines of:
(Brian) So, you wanted to use another language and simply introduced it into production?
(me) More or less.
(Brian) Do you think that's the most effective way for organizations to select languages or frameworks?
The first response to the question was the obvious and appropriate one:
That sounds better than a CTO making a decision while drunk and on a golf-course with a vendor. -- Josh Graham
Of course, I agree with that response, but that doesn't mean that my choice was the best answer either. The question is actually something I've been struggling with for awhile. At speakerconf Aruba 2011, Lyle (DRW CTO) gave a presentation on how we do things at DRW. One of Lyle's slides listed each language that we use in production at DRW. There were a lot of languages, probably around 25, and Dave Thomas questioned whether it was a positive or a maintenance nightmare. The answer today is the same as it was then, so far the ROI is positive - but, I couldn't help feeling uneasy about the situation.

I answered somewhat noncommittally, along the lines of: While selecting a language, I chose one that I felt anyone in DRW could easily learn and use. Additionally, I selected a language that aligned with our business goals of developing software quickly and delivering applications that performed at the speeds required by the traders. And, if not the man on the ground, who is better suited for selecting languages to introduce into production?

Brian followed up with:
The point I was trying to get at was: how does this scale? If every developer chooses what is best for them, is that necessarily best for the organization? How do we balance between the business value of increasing individual productivity and the business value of reducing maintenance costs or development risk? If we have to make compromises to achieve better scale, who should make these decisions, and how?

The usual developer argument -- "this is more productive for me, and increasing my productivity is good for the company" is good as far as it goes, but most developers incorrectly assume these interests are 100% aligned when they are in reality probably only merely overlapping.
These are truly great questions, and no one had a great response. The discussion basically died off as we pondered the tough answers to these questions.

At lunch the next day I asked Brian how he thought companies should go about selecting languages, and I think his response was spot-on (again, going from memory, so likely misquoting): I'm not sure, but I sure do see a lot of developers introducing whatever language or framework they want, leaving within a year, and sticking their employer with a big maintenance problem. The same can be said for consultants. They often show up advocating a sexy new language, mostly deliver a new application and then leave the company with an application that can't be maintained by the existing full-time staff.

Someone quickly spoke up, stating that Resume Driven Development has been going on for years. I can't argue with that, but I did have a different perspective.

A few years ago I joined DRW, and a substantial portion of my salary became bonus money. I had previously worked in places where getting bonus money was about as likely as meeting your future wife at a JavaOne, so I was obviously skeptical. Luckily, I had a friend who already worked for DRW; he reassured me that, in finance, having a bonus as part of your compensation was common, and so was it actually getting paid. I took the job, and instantly my performance at work was more directly tied to my income. I'm sure this reality influenced my decision making, and I witnessed the difference in the decisions my colleagues were making. When people spoke about using/upgrading frameworks/libraries, we didn't talk about what was cool, we discussed the risks of breaking things, the outstanding bugs with the framework/lib, and the immediate value that the inclusion would provide.

Given this experience, I advocated to the other speakerconf presenters that bonuses are a potential solution to combatting Resume Driven Development. The other speakerconf presenters gave me the same response I generally get when advocating bonuses for programmers: That works for you and your trading firm, but most people can't directly tie what they do to how the business makes money. I'm always skeptical of this response for 2 reasons: The business must be able to track whether or not their new idea is making them money, or, if the new software isn't targeted to an external customer, then it should be able to be rated by internal customers. Also, shouldn't the CTO or the Director of Software be able to make an informed bonus decision by either directly interacting with the teams, or trusting the feedback of the managers of those teams?

I guess, if you can't tie what you are doing to the value it's providing the company, and you don't trust your managers to give an accurate assessment, building your resume is probably the best use of your time... and the results aren't very surprising... but, I digress.

I gave the same response I've given a few dozen times: I just don't buy it. You should be able to see how many new customers your new website generated, or less cancellations, new reservations, policy efficiency, auction traffic, add-on sales purchased, etc. Each of the projects I've worked on for the past 8 years could generate metrics that I would have been happy to tie to a bonus. In our back-office, it's harder to tie the value of a back office system to an individual trade; however, we can capture metrics on uptime, latency, and any other attribute that we deem important to the internal systems that are customers of the back office systems.

If you want to measure your value and you trust your management, receiving part of your salary as a bonus is completely viable.

Aligning the goals of the business and the programmers came up again when the afternoon presentations began. Joshua Kerievsky is looking to tackle this same issue at Industrial Logic. Joshua's presentation discussed bridging the gap between managers and programmers, which is a more general version of the same conversation we'd been having about language adoption. Bridging this gap is something he's begun focusing on at Industrial Logic. The benefits are obvious for customers, they should receive higher quality and more relevant software. However, it's not just about customers, the programmers will be more effective and should also have higher job satisfaction rates. No one likes being stuck on yet another, doomed to fail, misguided project using outdated technology. Both parties should benefit by unifying the goals of the programmer and the business.

Josh knew my opinion on using bonuses to help align both parties; however, he and I both incorrectly assumed that the developers at Forward also received business performance based bonuses. I believe that they have some things in the works and situations can vary, but Fred George made it clear that in general a bonus is not tied to business focus. That's fairly standard, but what makes Forward unique is that the business works very, very closely with the programmers. I think Fred nicely summed up the situation: Our programmers are gamers, and we show them the P&L. They want to see that number grow, even if it doesn't directly deposit in their account.

Fred's statement rang very true to me. I've had jobs in the past where I didn't even have a bonus, but the ones that I felt most dedicated to were the ones where I was given visibility into the business. If I can't see the outcome of my programming choices to the business, I'll have a much harder time iterating towards success - worse, I won't even know at what level we are failing and I'll lack the motivation that the failure would provide me.

At the end of the day, programmers like to measure and improve. If you give them a P&L and let them know that it's the most important thing, they'll do whatever they can to help. If you don't give them a P&L they'll focus on making other metrics more efficient. This may include using new technologies to inspire more blog entires, spending hours unnecessarily tweaking the development process, or any other way of measuring their "success." The answer is obvious, let the programmers measure success the same way the business does, using the bottom line. What's not always obvious is how to properly share that information; however, all the discussion at speakerconf definitely convinced me that it's worth solving this issue even if it requires a bit of extra effort.

Wednesday, February 15, 2012

How To Get Invited To speakerconf

Every year it seems that someone is disappointed (or even insulted) that they didn't receive an invite to speakerconf. If you haven't gotten an invite at this point, contrary to popular belief, it's not because Josh and I hate you. There's actually very little magic that goes into receiving a speakerconf invite, so it probably makes sense to put the formula out there.

I'm not a big fan of receiving spam, and while I consider speakerconf to be a great event, I'm sure some people will consider speakerconf related email to be spam. With that in mind, I generally don't like to email people I don't know out of the blue. Along the same lines, some people are going to politely decline every invite I send their way. The less I know you, the less likely I am to continue inviting you, simply because I don't want to bother you. If you say to me "please keep me in mind in the future," I will. If you don't, I'll likely default on the safe side of not bothering you until you show some interest.

So, if you haven't gotten an invite lately (or ever) it's likely only because I don't want to bother you.

With that out of the way, here's roughly how we select who to invite to speakerconf:
speakerconf needs sponsors to run in the way that Josh and I want to run it. If you've previously attended a speakerconf you can guarantee yourself an invite if your company is willing to become a sponsor. If you've never attended a speakerconf you can also guarantee yourself an invite by getting your company to become a sponsor and getting an endorsement from any one of the speakerconf alumni (list available at http://speakerconf.com/speakers). If you are interested in discussing specifics, drop me an email (jay@jayfields.com).

If you're not interested in sponsoring, your invite depends on space or endorsements. If you've previously attended a speakerconf and you'd like to return, all you need to do is let me know. If we have space at the next event, I'll gladly extend you an invite. If we don't have space, I'll extend you an invite to the following event.

Future speakerconf events will likely have a maximum number of 20 attendees. Approximately 15 spots will be reserved for alumni, and the remaining ~5 spots will be available to anyone who has never attended a speakerconf. If you would like to grab one of those spots, all you need to do is get as many alumni as you can to email me and endorse you. They don't need to send a long email, something as simple as "you should invite Josh Graham to the next speakerconf" will do. Then, approximately 6 months before an upcoming speakerconf I will invite the 5 most alumni endorsed new comers.

That's it. If you want to join us all you need to do is to utilize your network or become a sponsor. Hopefully this view into the invitation process will help avoid any disappointment in the future.

Tuesday, January 24, 2012

Lessons Learned while Introducing a New Programming Language

I've used a lot of languages (professionally) over the years: (off the top of my head) Cold Fusion, HTML, Javascript, php, SQL, CSS, ASP(classic & .net), C#, Ruby, Flex, Java, & Clojure. Each language has pros and cons. Being a programmer, it's easiest to discuss the cons - and in general I believe it was best said:
I hate all programming languages - Matt Foemmel
I think it's important to start with this in mind. At some point you're going to hate what you're advocating, so imagine how other people feel about it.

In 2008 I introduced Clojure into a DRW codebase. This blog entry focuses on the adoption lessons I've learned in the past few years.

Language Selection
Introducing a new language to an organization isn't an easy task; if you're going to succeed you're probably going to need to pick a language that satisfies a large technical need and is also considered socially acceptable. I was writing Java 100% of the time when I joined DRW, despite the fact that a large portion of the code I was writing only needed to run in eye-ball time (250ms). Java was absolutely the right choice for the Faster Than Eye-Ball Time code we were writing, but using Java for the other code always made me feel like I was unnecessarily paying the Java verbosity tax.

On occasion I would mention the Java verbosity tax, and I found that my boss was actually interested in looking more closely at JRuby. I think JRuby would have been a win for us, but for me it was more interesting to hear that I had an ally if I wanted to explore non-Java options. If JRuby was on the table, then I knew that any high-level, dynamically typed language would also likely be on the table.

However, before I'd even discovered any JRuby curiosity, I'd already begun looking into Haskell. Generally, software in trading firms needs to run "fast." If I was going to successfully introduce a new language it was going to need to run "almost as fast as Java." I'd heard good things about Haskell's speed, and it also fulfilled another adoption desire of mine:
A language that doesn't affect the way you think about programming, is not worth knowing - Alan Perlis
I believed that if I found a language that was "performant enough", allowed us to deliver at a faster pace, and improved our programming skills then the level of effort required for adoption would be justified.

I toyed with Haskell for a bit, but the adoption path seemed a bit too steep. There's the effort it takes to learn Haskell, but more importantly: we were already on the JVM. If I was going to get any support, I needed something that was easy to sneak into our existing infrastructure. Enter Clojure. Clojure is performant enough, more succinct than Java, and sufficiently different to anything else I'd previously worked with. Clojure is also dynamically typed and high level (like Ruby), so I was hoping to get some support from my boss.

Causing my teammates as little pain as possible was a very large requirement - I believed this was key to gaining adoption. Clojure appeared to be the best choice due to the fact that we were already using:
  • IntelliJ all day
  • JUnit to run all of our tests
  • TeamCity for CI & artifact creation
  • The JVM on our servers
  • Yourkit for profiling

Clojure was the language that gave me everything I was looking for and had the easiest adoption path for the rest of the team.

I would have preferred Haskell or OCaml from a learning perspective, but they didn't seem like practical choices - and I doubt I would have had as much success getting them in production. While I need to be an expert in many things Clojure related, I relied on the JVM server settings that someone else has determined to be "the best". If I had chosen Haskell or OCaml I'd have had to become an expert on a much larger scope of topics (e.g. deployment, memory model, libraries, new tools, etc).

I believed then, and I still believe today that Clojure was the best choice given our technical needs and the social context.

Hello World
Introducing a language is a delicate act. There's a bunch of valid concerns that you're going to need to address. I wasn't exactly sure how my teammates were going to react to the introduction of Clojure, so I wrote the original code in my own time at home. I knew that we needed some integration tests for our application; however, no one was actively working on implementing anything. I began by writing them in Java and then wrote Clojure versions as well. I knew enough Clojure that I was able to showcase it's succinctness - something I knew the team would value in integration tests. Additionally, since the tests aren't part of the production running code there were no real speed concerns to consider.

Integration tests are a good place to introduce a new language, but any non-production code will probably be an equally good choice. For example, you could also choose database migration scripts, log file parsers, 3rd party software simulators, or deployment software. As long as you pick something that can fail without too much immediate pain you should be able to easily recover from any adoption issues.

After I had both sets of tests complete I showed both versions to the other developers on the team. I pointed out why I preferred the Clojure versions and asked if they would be willing to give Clojure a chance. I also made commitments that made it hard for them to say no to the experiment.

Your Commitment
I eased my teammates adoption fears by making the following commitments.
  • If you want to work on the code I'll work with you (if you want me to work with you).
  • If you don't want to work on the code I'll fix anything that's broken.
  • If the initial pain of working with a new language becomes unbearable to you, I'll rewrite everything in Java on my own time.
Obviously you'll need to get team buy-in before writing too much in your new language - otherwise you could be setting yourself up for working a lot of nights and weekends.

Tool Support
Chances are your team already has a tool-chain that they are happy with. Whatever that tool-chain is, your new language is going to need to play well within it. For me this meant being able to execute Clojure code within IntelliJ as easily as Java. For the most part the La Clojure plugin does the heavy lifting; however, I did need to write a testing framework that allowed me to run focused tests and seamlessly integrated with our existing JUnit test suite. The main point here is to remove any adoption friction that your team may be feeling. Learning a new language is a reasonable request, but changing the way a team works simply to accommodate an unproven (on that team) language choice is probably too much to ask.

You may also need to make some sacrifices as well. I prefer to write Clojure in emacs; however, I'd rather be writing Clojure(where appropriate) in IntelliJ than writing Java in IntelliJ. During the early/fragile adoption time, you're the one who's going to need to do the majority of the compromising.

Find allies
Chances are you'll have varying levels of interest in your new language. During the early days you should do anything you can to encourage others when they're interested; however, you don't want to push anything on anyone - that's the easiest way to find enemies. Hopefully you'll have a few teammates who are also as excited about a new language as you are - work closely with them on improving both of your skills. You'll want to get as many advocates as you can, otherwise you'll end up looking like the lone team member forcing the team to do something they aren't comfortable with.

It's also inevitable that you'll end up needing more research time, needing tool support, and dealing with more production issues than you originally anticipated. You're going to need a few other people to pick up some of the slack when you find yourself overextended. Even when things are going well you'll find yourself in need of allies to help you support the growing code written in a new language.

Lastly, the worst case scenario is you leaving a team and no one is left on the team that wants to support that code. It's pretty easy to see how a staffing situation can be portrayed as an adoption problem.

Know Everything
Obviously you can't actually know everything, but you're going to need to have an answer or be able to quickly get an answer to anything that comes up. You'll definitely want to read a few books on your new language before putting it in any codebase that your team members also work with or rely on. That's likely not enough though, you'll also need to know where to go if you run into issues. For Clojure this was the IRC channel for immediate answers and the mailing list for less time sensitive issues or issues that required a bit more explanation. If you're really looking to cover your bases you'll want to have some type of relationship with the creator or one of the community leaders.

Once people start adopting the language you introduced they're going to start doing things you didn't anticipate. You're going to need to know the dark corners of the language and the associated corner cases that exist. You'll also need to be an expert on issues such as memory allocation, performance, deployment, tool integration, library support, upgrade schedules, and everything else that is outside of the language's syntax.

The more allies you have, the less you'll need to 'know everything'; however, at the end of the day you're going to need to know as much as possible. If things ever go wrong, all eyes are going to be on you. That's the level of commitment you're making by introducing a language, so you better know what you're getting into.

Get Help
If your company is willing to let you introduce languages then they are probably a fairly supportive organization. Hopefully you'll have a bit of a training budget. See what opportunities you have for bringing in the language creator or the community leaders to work with you or provide training. If you're having issues with anything, having the creator of a language work with you is obviously a huge advantage. However, if things are going well it will probably benefit you to give up your training budget to contribute to a pool that could cover some training for other team mates who are interested in learning from the language's creator (or a community leader). Whether it's for you or interested allies, utilize your companies training budget to encourage adoption.

Be an Advocate, not a Zealot
At the end of the day it's not likely that everyone is going to have a compatible opinion. That's fine. Don't push your opinions on people who aren't interested. On most occasions the 'right' choice is the one that someone is passionate about. You might be passionate about your language, but a teammate of yours might be passionate about the old language. Neither of you needs to be right or wrong. People should work with what they are passionate about, and any attempt to make them work in another way is likely to do more harm than good. People who want to work with the new language will find a way to organize themselves together and people who don't will do the same thing. There's no reason to force adoption.

Originally, I approached the problem as "If I create a clearly superior solution then everyone will want to come along." This definitely turned out not to be the case, thus the blog entry on compatible opinions on software. I learned that one person's "obviously better" is another person's "obviously worse." In the end the team ended up organically dividing into people who worked on the Clojure code and those that didn't. This worked out well for both parties, as the people who wanted to work with Clojure had enough available to them, and the people who didn't weren't forced to.

The divide was more of a practice than an official split. We were all still part of "one team"; however, we tended to work on separate applications that communicated through messaging or not at all. I advocated strongly for a team split based on incompatible opinions and size (we were at 7, and I thought 4 and 3 would be fine), but we never ended up making anything official. Eventually other factors changed and the team shrunk to a size where a split was no longer necessary. I still believe splitting would have been the best solution if the team hadn't reorganized for other reasons.

The End
Introducing a new language is likely a multi-year affair for any moderately sized organization. There's not likely an "end" where your responsibilities go back to what they were before introducing a new language. On the flip-side, you get to use what you consider to be the best tool for the job. Hopefully it's worth it when it's all said and done. Personally, I'm happy with my choice, but I expect to be learning new lessons on this topic for at least the next few years as well.