An interview with #erlang cowboy Loïc Hoguin (@lhoguin)
Hello guys! Today I will interview Loïc Hoguin. Loïc is the author of the Cowboy project. He is also the founder of the company Nine Nines. He will give us some information about his project and his experience with Erlang. Enjoy!
Every gun makes its own tune, and every project has its own author
Paolo – Hi Loïc, it is a pleasure to have you here! First of all, would you please tell to our readers something more about you?
Loïc - Howdy Paolo. Sure, this Cowboy ain’t got nothing to hide. Not much to say about me, I’m that guy who was never interested in studies and dropped out of enginnering school twice to then start his own company.
I’m also an indie video game player, only listen to Touhou arranges and gladly make the trip to Tokyo just to attend the Flowering Night. Professionally I currently run the Nine Nines company that I founded early this year. We are doing consulting, Erlang training (in french and english) and support for our open source products. http://ninenines.eu
Paolo – Why and when did you start with Erlang? How would you describe your experience with this language and its community?
Loïc - I started with Erlang early 2010. I was tired of doing PHP professionally, the alternatives like Ruby and Python didn’t sound that much sexier and ultimately found Erlang. I found that Erlang’s concurrency and fault tolerance were great assets in today’s web. So I started learning Erlang and using it on a personal project, a private server for the Phantasy Star Universe game. https://github.com/essen/egs
One year later, while still working on this project, I realized I needed a generic acceptor pool that could handle all the different protocols + HTTP for the website, tied directly so we could have live data from the server. Then Cowboy was born.
Paolo – The first commit for Cowboy was in March 2011, while the first beta was ready in September 2011. How did the Cowboy project evolve after that?
Loïc - It evolved a lot. Since then we have re-implemented the Webmachine REST diagram, added a static files handler based on it, improved Websockets, and continued to improve the product.
These days a lot of the development comes in the form of user contributions. Users have been awesome and I want to thank everyone who helped us, either through bug submissions or patches.
Paolo – How would you describe Cowboy architecture in a nutshell? Where can our readers find more information about it?
Loïc - Cowboy is acceptor processes accepting connections and sending them to connection processes for handling. All transports (TCP/SSL) use a common interface and you don’t have to worry about which one is being used.
Cowboy includes an HTTP protocol complete with REST and Websockets support. It will all be documented in details in the documentation coming for 0.8.0.
Paolo – What are the main benefits of using a pool of many processes accepting connections? Is there any drawback?
Loïc - On multicore CPUs, you can accept a little more connections if you have more than one process. Performance can drop if you use too many of them though. I have found that 100 acceptors is a reasonable number on most systems. It probably should be tweaked if you need to make the most of your capacity.
Paolo – How does Cowboy differ from other Erlang projects as Misultin, Webmachine and Yaws?
Loïc - The biggest difference is the use of binaries instead of lists. The generic acceptor pool is another. I could list a lot of other small differences but I figure these aren’t the most interesting.
One big difference is how Cowboy is designed. There are two key points to how I design Cowboy.
The first is that I try to support well 99% of the use cases. I don’t really care about the remaining 1%. If a company needs something so specific that only they would use it, they should patch the source. Similarly, if someone tells me it would be a good idea to add a feature, I ask what the use case is. I don’t care much about feature ideas, I care a lot more about why and how people expect them to be used.
The second is the realization that today’s HTTP works pretty much like a gen_server, except the client talks to us through the network. So when you write a Cowboy HTTP or Websockets handler, you write it pretty much like a gen_server. You init the process, handle requests or messages and clean it up at the end. This isn’t an actual gen_server of course because we have to take care of the connection and I didn’t want to have two processes for a single connection.
Paolo – It is often said that “Cowboy represents a very good example of Erlang clean code” since it doesn’t use process dictionaries or parametrized modules. Can you tell to our readers why you excluded these features from your project?
Loïc - The process dictionary is pretty much equivalent to mutable global variables. Hard to test, hard to debug, process-dependent, implicit.
Parameterized modules are an oddity. When you call Req:do_something(Var) you end up actually calling do_something/2, even though you provided a single argument. This is also at odds with Module:do_something(Var) which calls do_something/1 if Module is an atom. This is all too confusing. The other problem is that Req can’t change and that means we can’t do all the lazy evaluation of the request and we can’t keep state in the Req object.
Generally I avoid anything that is implicit instead of explicit. It’s better to write a little more code if that means people can read it more easily.
I believe the “clean code” comment is also because Cowboy has typespecs, eunit and ct tests, clearly documented API and modules written in a top-down fashion with clear function names.
Paolo – Cowboy is also said to be very good in terms of memory saving. Can you expand a little bit this part of your project?
Loïc - Since we use one process per connection instead of two, and we use binaries instead of lists, we end up using a lot less memory than other projects without user intervention. Cowboy is also lazy, it doesn’t do anything unless required. So we don’t have much in memory until the user starts calling functions.
It also supports hibernate for long-running processes, in a similar way to gen_server.
It also has a compact/1 function to remove all non-vital values from the Req. This one is only possible because we didn’t use a parameterized module.
Paolo – Is it true that in future versions the acceptor pool part will be separated from the rest of the code? What is the reason of this choice?
Loïc - Yes the acceptor pool is now the Ranch project: https://github.com/extend/ranch
The main reason is that Cowboy does two things, and I believe applications should do only one thing and do it well. So the split was planned a long time ago.
I also received a lot of comments from people wanting to use the acceptor pool but not able to unless it was separated from Cowboy (for various reasons).
The split actually allows me to simplify things in Cowboy. To start a Cowboy listener for example, that means an HTTP one, you can simply call cowboy:start_http/4 instead of the old cowboy:start_listener/6. I can make assumptions that I couldn’t before.
Paolo – What else can we expect from Cowboy in the future? Maybe support for other non HTTP protocols?
Loïc - The 0.6.1 version will fix a few bugs from 0.6.0 without breaking the API. Then 0.8.0 will come with the switch to Ranch and various API changes. Hopefully we can squeeze all the API changes we want in this version, so that this doesn’t happen again before 1.0.0.
Cowboy is HTTP. You can probably expect a SPDY protocol handler since this is still HTTP related.
Now that Cowboy works, it’s time to make it pretty, and then we’ll make it fast. Making it pretty means breaking the API here and there to fix inconsistencies and improve the general user experience. This is the part where we’re switching to Ranch and adding functions to more easily write a dispatch list. Once that is done, we’ll focus on optimizations for a while before releasing it as stable.
The exciting development is going to occur in Farwest, which will include all the tools needed to write a web application, including sessions, auth, presence server and more. https://github.com/extend/farwest