We are starting a rewrite of a project that has lived for close to 7 years. The original project was a desktop application for Windows using WPF. We feel pretty strong that desktop applications are not only harder to support, but also in the case of WPF it limits our ability to easily support anything but Windows. In the case of the current application we have turned away business that otherwise might have added significant value because of this.
You might have also realized that our company has heavily invested in FubuMVC over the last several years. However, when a “rewrite” was mentioned our CTO suggested doing a holistic evaluation of our current stack rather than starting with our typical one. This lead us to come up with a set of primary goals that we would be looking for in a new stack were we to make a switch. DISCLAIMER: These goals were important to us and we understand that opinions are subjective and depend on the context. Don’t use our opinions to shape your own. Instead I would recommend that you come up with your own goals and do a similar evaluation. Maybe you’ll find the opposite to be true.
- Testable – Testing in .NET, and specifically TDD in .NET often feels like an awkward second class citizen. We want TDD to feel as natural as possible. Ideally some sort of auto-test runner would help in that regard. In addition to unit tests though, integration tests are extremely important and should run in isolation from each other not dependent on any shared state or database.
- Fast feedback – One thing for sure that we have learned is that the tightest feedback loop keeps us the most productive. Auto-tests for the testing portion, but in the case of building the webpage(s) using something to auto-reload the page on file save would also be ideal. We should stay in our editor as much as possible and never need to lose focus on the task at hand.
- Simple editor – Many of us in the office are already VIM users and although many IDE’s have vim emulation it often just left us wishing for the real thing. For others, textmate, or Sublime Text shouldn’t be out of the question either. The big theme for us though is that it’s just text and we shouldn’t be waiting on our environment to begin typing.
- Good OSS community – This is commonly one of the largest complaints about .NET (although it’s improving) and we want to experience and participate in these communities we so often hear about. An additional criteria was that the community was growing and not shrinking (but still large) like the ruby community.
- Scalable – While this project specifically has a very fixed scale, the longer term possibilities of using on other projects is a strong liklihood if things go well.
With that set of criteria we spent some time researching what our options were with a few obvious contenders on the list. The primary contenders that we spent time with were Node, Scala, and Golang. Others that we gave less serious time, but still evaluated were F#, Erlang, Haskell, Rust, and Dart.
Scala from the outside seems to be growing in popularity with some big name companies on their list of adopters. This was a strong favorite going into the evaluation and to many of us seemed like it would win in the end. Several of our developers have taken both the Scala course and the course on reactive programming from Coursera. Upon completing those courses a couple of our folks began to build a project with the Play framework and Akka. The project itself was a dashboard for github statistics that were more organization and team specific rather than repository specific.
During the process of building something real there was a very real cost of learning vs. being productive. The two people we had working on this are two that are probably the most experienced and competant people we have. Despite their competancy the ratio of learning and understanding vs. doing was probably somewhere around 4 to 1. Some of this can be explained by the JVM being relatively new to us. However, complexity complaints is not a new thing for the Scala community. Before building something real I think the mindset was a bit of arrogance that sounds like “we laugh in the face of complexity, others are just not smart enough”. The complexity is real and one that even extremely experienced Scala developers have mentioned as well. Surprisingly some of the complaints in that rant that are “edge cases” that should be hidden away are things we ran into in the first week. How did it do against our goals though?
- Testable – This was honestly one of the most time consuming parts of our research. Although there is a rich set of testing tools. Techniques on how were often never mentioned, or required extensive time digging through the sources to find the implicit variables that would cause us to trip up. There’s plenty of people testing in Scala successfully sure, but it’s still something we considered lacking or at least not better than what we had in .NET.
- Fast feedback – Most of the time Scala compilation and feedback loop seemed as fast or faster than what we had experienced in .NET land. However, there were several times that we would see spikes in compilation time that would take as long as 18 seconds for a very small project.
- Simple editor – 1 person had success with this in VIM Scala workflow, but others felt it was more natural with IntelliJ.
- Good OSS community – There is a good community in Scala and a lot of really smart people solving complex problems. The statement is also made that you’re inheriting the Java community as well. However, in practice we found that consuming Java libs in Scala never quite felt right. Nice if it was necessary, but often we looked for Scala libs first and only if we couldn’t find a good one would we fall back to Java.
- Scalable – I don’t think there’s a lot of question on the scalability of Scala.
All in all Scala isn’t bad. It didn’t measure up too well against our goals though. When we were running the website with auto-reload and our auto-tests going the feedback loop averaged around 10 seconds. Not awful if only comparing against .NET, but as we’ll see in with Node and Golang it wasn’t in the same league anymore.
When we began this research Golang wasn’t even on our radar. However, with the popularity of docker, etc. it naturally brought some attention to golang and is why we added it to our list of things to evaluate.
Golang is ridiculously fast both for compilation and during runtime. The memory footprint is also very small compared to our .NET experience. Golang felt as fast as a dynamic language, but provided the compile time safety we were used to. Overall it felt very promising even though it had never been on our radar before. I spent two days learning the language and honestly felt extremely productive, but how did it measure up to our goals?
- Testable – The testing tools out of the box are awesome. Other communities need to pay attention because this was one of our favorite aspects about golang. Goconvey is what I used while learning the language, and flowed right into my workflow when I began spiking real work. In addition, the standard testing tools provide coverage and benchmarking capabilities which keeps the decisions on which tools to use dead simple.
- Fast feedback – Like I mentioned previously, golang is FAST. Nothing we tested compared to the speed of golang. When using auto-reload as changes were made I never saw any request go over 12ms and more typical I would see requests around 6ms. It was the first time I’ve really considered things in terms of microseconds.
- Simple editor – I initially started using Sublime Text 3 with golang and found it to stand up pretty well, but later switched back to vim due to some flakiness in some plugins that had been updated. I landed on the vim-go plugin and felt that it kept me very productive and had features I wouldn’t have expected in a text editor.
- Good OSS community – The community is gaining a lot of popularity and it seems that a day doesn’t go by without hearing about another company switching to golang. However, in our opinion the golang community, specifically for web development needs a bit of maturity.
- Scalable – It’s claimed that golang will be the language of the cloud for a reason. The speed alone buys you a lot in terms of scale, but in addition golang makes concurrency extremely simple and elegant.
While as you can tell from my tone that I was a big fan of golang. I couldn’t disagree with my colleagues that the web development community needed to mature a bit. Even though it wasn’t a primary goal, we didn’t want to do a ton of road paving. Before anybody goes on a rant and mentions revel, beego, martini, or “you don’t need anything more than HandlerFunc” we felt that each one of those frameworks or approaches came with drawbacks that conflicted with one or more of our goals. My next post will go into much more detail about how and where I think the golang web development community could improve because it’s not the point of this post and it deserves a lot of detail. In a somewhat unfair opinion though, I could summarize a lot of the community is full of individuals writing “frameworks, non-frameworks” and shouting at the world “look how awesome this is” and reinventing the same wheel all over again. I almost fell into the same trap myself as you can see https://github.com/CoreyKaylor/gonion/blob/master/integration_test.go . I bet you’re surprised that it wasn’t because golang doesn’t have generics. If you’ve heard those things and dismissed go, I would spend some time writing some real code with it and see if you still think it should be ignored.
Node was an obvious thing to evaluate. The community has a ton of popularity and is where it seems that much of the ruby community has migrated. One of the drawbacks in my opinion is the single thread programming model. While it simplifies things in some cases it complicates things in others. However unlike ruby, node scales very well even with the single threaded model due to it’s non-blocking async by default nature. How did it stack up?
- Testable – The testing tools are very good as well. Generally, I think testing tools in dynamic languages tend to be beter than static ones because they are absolutely necessary. Don’t read into that and draw conclusion that I’m saying testing is less necessary in compiled languages, but I do think people get away with it much more often (even if I consider it unprofessional to do so).
- Fast feedback – This is also one of the natural outcomes of a dynamic language. No more compilation step necessary so the feedback loop was very fast.
- Good OSS community – Also obvious that the community would be good. There’s a ton of momentum in node and some really great projects. For example passportjs is something that the golang community is severely lacking. That’s just one simple example, but the ecosystem was one that we felt confident that we wouldn’t have to do much road paving in.
- Scalable – We have small concerns around the longer term scale questions, but for our immediate project needs there’s no question that it can handle the demand. Even with our longer term concerns we know it’s not a question of can, but rather how and at what cost of complexity.
Why the “For Now”? I honestly think within a year or two golang will be nearly impossible to ignore. It has a lot of momentum and if the community can learn to move forward together and use those implicit interfaces they’re so fond of there will be no stopping it from getting more adoption.