Before I started at Think Smart, I did the rounds in the London start-up scene, looking for early-stage projects that had an interesting product proposition with interesting tech behind it.
On company I spoke to were launching an e-commerce venture that had a small range of products that it wanted to sell to a broad audience. I won’t go into the details, but they were working on the assumption that for any potential customer who visited their site, there would be one particular product from their range that would suit that customer best. So their website needed to first identify the best-fit product, and then sell it to the customer.
The founders had a little cash behind them, and had hired an agency to build their MVP. They were now looking for a CTO to take the agency’s work in-house, prior to their public launch. The agency had built the front end using React, used an open-source Rails engine for the actual online shop, and then a recommendation engine using Elixir and Phoenix.
I got in touch, and spoke to one of the founders, who was very optimistic about the future of the venture. Then I was passed over to the tech lead from the agency, who kicked my tyres over the phone, to assess whether I was technically competent to take over development. After half an hour of fairly informal coder-chat about my CV, I was given an opportunity to ask some questions. The one that leapt straight from my lips was, ‘So why did you choose Elixir for part of the back end, if you’d already committed to using Ruby for the rest?’
The tech lead gave me three reasons:
“We wanted to make sure we kept the recommendation engine separate from the e-commerce engine, and using a different tech stack enforces that. And we thought the recommendation logic would be well suited to a functional style, whereas it would all get a bit messy if it ended up inside an ActiveRecord model. And Elixir is a straightforward language – any developer worth their salt should be able to pick it up easily.”
Oh dear. What alarmed me about the response is that none of the above is a reason to use Elixir. At best, they’re reasons not not to use Elixir, which is a separate thing entirely. If you don’t have the discipline to keep your code modular without building each piece in a different language, then you’ve got serious problems. Likewise, if you’re writing primarily in Ruby/Rails, and you’ve got a piece of logic that you want to write in a functional style and not get tangled up in an ActiveRecord model… well, you could always just write it in a functional style and not put it in an ActiveRecord model.
But it’s the third reason that I have particular issues with. This idea that programming languages are all much of a muchness, and you can swap them out howsoever you please. After that conversation I spent a week or so trying to articulate why I think that’s not a sensible approach, and I think I can best sum it up with the following question:
“What are the top 5 architectural/structural mistakes that Elixir/Phoenix coders tend to make, and how can you avoid them?”
What’s notable about that question is that I suspect the agency tech lead would have been unable to answer it quickly. In fact, I suspect there are very few people in the world who would have an answer for it at all. The reason is that less than 2% of web developers use Elixir, according to the Stack Overflow 2017 developer survey. There are barely 4,000 questions on Stack Overflow tagged Elixir and only 400 tagged Phoenix – whereas Ruby and Rails have 180,000 and 280,000 respectively. Elixir/Phoenix simply doesn’t get enough use for the community at large to have definitively explored the pitfalls that the technology strays near.
Now, imagine asking any experienced Rails developer the same question about their technology. I can promise you they’ll have an answer. They’ll probably struggle to limit themselves to 5. (Let’s see… fat controllers, fat models, too-close coupling between controllers and views, cluttering up the global namespace with helpers, undisciplined use of the messy ActiveRecord API, controller specs, ad-hoc tasks shoved into lib/tasks, ad-hoc tasks shoved into migrations…).
And this stuff matters. Even though Rails is a more opinionated framework than most, every technology encourages a particular structure, a particular style, and the direction the technology pushes you in should always be treated with caution, because what works in some situations won’t work in others. If you get it wrong, you accumulate tech debt. If you accumulate tech debt, your velocity decreases. If your velocity decreases, your ability to respond to opportunities diminishes, your ability to push out new features diminishes, your ability to survive as a start-up diminishes.
Now, I’m not saying that you should only work with tried and tested technologies for a start-up. Not at all. You should work with the best tool for the job. If that’s Elixir and Phoenix, use Elixir and Phoenix. But you should be aware that the less established the technology, the higher risk it is. What I can’t abide is letting the natural magpie tendency to want to embrace the new and shiny overwhelm one to such an extent that one ignores that risk and hides behind utterly trite arguments such as the ones the agency tech lead offered me.
Does this create a Catch-22 for Elixir? If developers avoid it because it’s not firmly established it will never become firmly established, of course. But I’m not saying we should all avoid less established tech. I’m saying that if you work in an early-stage start-up you should avoid less established tech unless you have a damn good reason to use it. And given the wealth of established, powerful and versatile languages out there, the situations where a start-up is better off using Elixir/Phoenix than, say, Node/Express, Ruby/Rails, PHP/Laravel, Python/Django etc are few and far between. For the most part, we should be leaving the Elixirs, the Groovys, the Clojures of the programming world to the established companies that can afford to get some things wrong, to accumulate some tech debt, to experiment and fail in lower-stakes situations.