About a year ago, my team started working on a Phoenix app. We all had experience with Erlang, building web servers, and software development in general. None of us had experience with Phoenix, though, so we followed patterns encouraged by the official docs, generators, and other independent blogs. We started with Phoenix 1.1, so there were no context, and there were still models. We moved quickly, and produced a lot of code in the next few months. Unfortunately, that lead us to a quite interleaved code with unclear boundaries and responsibilities. It became increasingly harder to maintain and extend such code. Some six months after we started, we agreed to clean up our controllers, and move other concerns to “service” modules (which I feel resemble the official contexts being introduced with 1.3). To this date, our code is still not completely there.
My takeaways from this experience are:
- Framework plays an important role in determining the code organization. Even as experienced devs, we simply stuck to defaults promoted by Phoenix at the time.
- It’s much harder to refactor the code post-fact. Having worked on some terrible legacy (and sadly produced some of my own), I strongly feel that your only chance of keeping the control of your code is to pay attention to it from the very start.
- Keeping the Phoenix part of the code (controllers, sockets) focused only on HTTP related tasks, basically making it just the interface to the rest of the system is a very good way to structure any production app.
Therefore, there’s no doubt for me that contexts are a very good idea which will push developers in good direction, promoting better code organization patterns. I agree that this will make things slightly more confusing for newcomers, because it’ another idea they have to grasp. However, I think that this is a good trade-off. A bit of approachability is sacrificed to get much better code organization.
I’m somewhat worried about this mantra myself. I have a feeling that for some people it means “Phoenix is not your OTP application”, and that we should always organize our system as umbrella apps. I definitely don’t share that view. For me, the core idea here is that Phoenix is an http/ws interface to your system. You take the input, validate it, and then invoke some other part of your system (i.e. some function from some module in some other namespace), and finally convert the result of that function into desired output (html, json, …). That’s a clear separation of responsibilities, and can lead to much more readable code. And a readable code is a win for everyone, especially for newcomers.