Reimagining a new Elixir web framework with no Rails roots or MVC/*VC

Hi everyone, I’ve been thinking about Phoenix and its evolution, and I wanted to share some thoughts.

Remember how Phoenix was heavily influenced by Rails when it first came out? The routes, models, views, controllers, and overall structure felt very familiar to anyone coming from Rails. Then they added contexts, which was a bit of a deviation, but still, many of the core concepts remained Rails-like.

Now, with LiveView, Phoenix has really carved out its own identity. It’s exciting to see how it’s evolving, but I can’t help but wonder if we’re still carrying some unnecessary concepts from the Rails world (disclaimer: I love Rails).

Don’t get me wrong—I think it’s great for beginners, especially those coming from Rails or similar MVC frameworks. They can pick up Phoenix quite quickly. But here’s the thing: Elixir is a functional language, and sometimes I feel like the current design doesn’t fully embrace that.

For example, instead of having an EventController (which would be EventsController in Rails), what if we had a more generic Controller module that we could pass our “events” table or other data to? It feels like that would be more in line with functional programming principles.

What if we had a framework that wasn’t influenced by any other framework at all? Not copying directory structures or naming conventions from other frameworks. Instead, imagine a library of modules and functions that we just pass data to. We could have a Route module where we pass in a link to create a route, a Controller module (or whatever we decide to call it) where we pass in the data and get the desired result. Functions from these modules could be piped into each other, forming a pipeline that handles everything from security to serving the request.

I think a library/framework like that could be easier to understand and reason about.

What do you all think? Is there already a library/framework out there that works like this? Would something like this be useful, or am I just overthinking it? I’m curious to hear your thoughts!

3 Likes

Phoenix is inspired by Rails as same as Elixir’s syntax is inspired by Ruby’s one. As same as languages share do … end concept as same web frameworks share MVC concept. They look similar, but may be completely different especially because of differences between OOP and FP. The more deep you go the more differences you see. Rails is nothing “special” here as just for example MVC concept has been created around 25 years before first Rails release. This is why it’s not really related to languages and frameworks. :bulb:

The core problem here are old concepts. A great example here is the X Window System. Many years ago it was absolutely amazing, but because it was based on old concepts it’s getting replaced by Wayland. Well … on one side Elixir and Phoenix are relatively new, but on the other one it’s based on old concepts like MVC. So … we are good here or not? :thinking:

To understand that better we need to know the Elixir concepts. One of them is extendibility. Elixir wasn’t created as a final solution for everything. Unlike in other languages we are able to extend it in various areas and the same could be applied to the Phoenix Framework or rather … the Phoenix Library. Phoenix as same as Elixir does not force on anybody any standards. No matter what the module name is you are free to use it under any file name. Phoenix is a library which means we can use only some part of it without a worry that we would need to support everything in a “framework”. :smiling_face:

With such a flexibility we have lots of possible ways. One of them could be a WebSocket-based API. If you want some solutions that work best in Elixir then you are free to use commanded and even ecto allows you to stream a data from database to the client, so the server does not have to load everything in memory. You don’t need to use a bulk actions or classic pagination when you use Phoenix. :rocket:

3 Likes

Then it won’t take off. Any new thing in software has to lean on existing concepts to reduce cognitive load for would-be adopters.

Also, any successful library will not break backward compatibility just to be cleaner. So Phoenix most likely will not change in the direction you suggested. However, you or someone else could publish a Phoenix TNG that lean on the part of Phoenix that you like and experiment in new direction in a breaking way. Maybe it will be successful and take over Phoenix Legacy in a few years.

4 Likes

I like exercises like this. We do things pretty differently, and don’t draw any true inspiration from other frameworks with Ash. It has pros and cons, we’re free to carve out our own paradigm, which is fundamentally different than anything else out there. For instance when building APIs with Ash, for example, you don’t write a single controller. Everything is derived from data. I think there is value in this thought process.

However, I think that its also important not to write off the similarities phoenix bears to rails as something akin to “well this was how rails did it so this is how we do it” type thinking. It’s a process of refinement, taking what worked well and what didn’t. If you are looking to reimagine a web framework from first principles, you’re going to have to solve a whole host of what I think are pretty surprising problems in the process.

For example, the typical problem with “one big controller module” is searchability. i.e how do I go and find the subsection of that code that handles requests from some given route. If I have to read a big pattern match to find the function head/case statement in question then I’m having to load up way more complexity in my brain to find what I’m looking for. If controllers are in their own module, I can fuzzy find files with “<thing I’m looking for> controller” and have a pretty solid hit-rate. So we end up doing things like having a case statement that calls a function on a nicely named module in a nicely named file so we can find the logic in question.

Couple that with the fact that 9 times out of 10 you end up with a controller-per route/group of routes, and the next big idea would probably be to put in your route handling code the ability for it to specify its own destination controller module, that way its super easy to go from route to controller, and then congratulations you’ve built a Phoenix router plus roughly the current controller convention.

I don’t say this to discourage this kind of thinking/work, as someone pushing against the grain myself! My goal is only to point out that it requires, I think, concretely better alternatives to what are out there and also wholistic thinking about why things are the way they are in today’s popular tools. For example, a lot of really simple patterns work amazingly in a small codebase with a small team, and fall apart when you start having 5, 10, or 100(:nauseated_face:) developers working on a large enterprise system.

So to answer your question more specifically:

It is entirely possible that there are alternative architectures to Phoenix that would be easy to reason about. But it isn’t inherently true because Phoenix bears some resemblance to and inspiration from something like rails. We’d have to talk specifics. The ideas of having one Route module and one Controller module do not sound like better alternatives to me on the surface.

12 Likes

That sounds like the goal of plug - “Compose web applications with functions”.

2 Likes

Yep, while Phoenix has MVC layout by default (and some magic that makes it work on some level like rails), all of its core functionality is around declarative data transformation pipelines.

It’s trivial, especially these days when everything is extremely well covered with documentation and examples to use plug + various parts from phoenix (such as heex) as standalone libraries and tailor them to your needs.

3 Likes

If you are after a fresh take, have a look at Aino. I haven’t used it personally, but the approach looks simple and elegant.

1 Like

It uses elli instead of Cowboy like Phoenix and Plug

It should be noted that cowboy is now one of two options in plug and phoenix, the other being Bandit — Bandit v1.5.7

1 Like

On that note, you may be interested in this project and related discussions:

2 Likes

Also worth taking a look at is Raxx and Ace by @Crowdhailer:

If i understand what you’re saying, I think you may be looking for the tools that phoenix is built on (namely Plug.)
A pipeline of Plugs is what creates controllers, after all.

You pass in a connection object to a function (a Plug) which parses the route in the object and based on that switches into other downstream Plugs that handle the request.
The combination of plugs makes a Controller as we think of it.

What phoenix really gives is a structure to begin working in. If you wanted to ignore that existing structure, you could use Plugs directly.

What in Phoenix do you find, at least a little bit, hard to understand or reason about?
Maybe that would be a good place to start refining your framework vision.

Thanks to anyone picking this up. I’m working with Bandit + Temple + HTMX with Postgrex at the moment.

I had to shake Phoenix off because I’m not a professional web developer working in a corporate environment. The aged concepts and approaches were too vast and peculiar to me. It’s disorienting without proper social/organisational environment. For me, it’s evident that a better web DX in Elixir can be. It just takes design-thinking, technical capability, and time, which I’m hoping to gain in few years.

1 Like

I don’t think there is anything special about Phoenix itself if we talk about it in isolation. I’m not a big fan of a few magical things that came from Rails but it’s also important to know where you draw the line between declarative programming (that inherently does magic under the hood) and the explicit approach. I think imperative frameworks like express in JS, while having the easiest concepts to grasp, don’t offer a good abstraction level to solve business problems, plaguing them with complexity down the line.

Those who don’t know the past are condemned to repeat it. Unless you take your time to understand where the value of Phoenix comes from, you will never be able to come with a better solution.

Instead of having the attitude that we need to throw everything in garbage and to reinvent everything, why not improve the existing things? I’ve followed all previous conversations related to alternative microframeworks, everyone that is against phoenix failed to formulate a valid argument against using specific features of phoenix (plug, html) nor their alternatives they implemented were even as close to what phoenix provides today.

5 Likes

Isn’t is great that sharing a vocal opinion about something does not have those requirements? Makes for great topics on this forum.

1 Like

While I would generally agree I wouldn’t take it as such an absolute. I think one can surely build something that’s easier to learn and understand than phoenix. However any programming effort is still a matter of tradeoffs. Just because something is simpler to start out with doesn’t mean it’s automatically simpler to grow and keep maintainable in the long term. Phoenix sits in a spot for people trying to be productive and building a system, which is going to be larger than a quickly bootstrapped one, hence coming with more upfront structure and with more pieces of “you’ll likely need this soon anyways”. Striking a balance on that scale is hard.

6 Likes

It troubles me when people get emotional when I share my frustration with Phoenix. :sob: And it happens too often than I like. I apologize if my experience offends anyone.

Phoenix is great, I learn from its codebase and I understand what it’s for. At the same time, my struggle is real too. Those are two facts that can coexist. It can be great and frustrate someone.

I won’t even be here from the first place (and learn Elixir) if I’m not willing to explore the hard, probably dumb ways. At the end of the day, I might not be able to provide anything useful. Do I have to? I’m hoping to contribute, talking about it, supporting other thinkers, not promising it.

3 Likes

Hear, hear. Any framework will feel too rigid to me. So, I don’t treat Phoenix as a framework but more as a library. I don’t use everything Phoenix offers and will use even less in the future. However, I still appreciate a framework that propped me up in the beginning. To me, subtraction is easier to manage than addition.

1 Like

This might have to do with your style more than anything else. And it might be some creditable feedback, instead of emotion.

I also would love to see another framework take a shot at the throne. But it would have to be better; which is easier said than done. Sharing frustration does not make a new competitor, sharing new ideas might.

Ps. From the creator of 3 Phoenix libs which ‘go beyond / break out of’ Phoenix :wink:

4 Likes

All I’ve seen are people pointing out that Phoenix or Plug on its own are already capable of doing what you’re looking for. All that is missing is easily discoverable documentation and guides on how to do it. This is a very solvable problem that doesn’t require writing a new framework. But to be clear, I am absolutely not discouraging anyone, including you, from writing their own framework. It’s just unfair to characterize Phoenix this way when it’s simply a matter of missing docs. Who will write these docs remains to be answered.

3 Likes

You mean the functions called Phoenix.VerifiedRoutes.url? and Phoenix.VerifiedRoutes.path? Or just Verified Routes with the sigil ~p?

All Phoenix.Router provides are macro’s. They write a lot of Plug boilerplate for you when you write something like get "/products/:id. But the resulting code is just a bunch of Plug calls.

1 Like