The news about plans for Symfony 4 has got a number of my dev team a bit excited about the possibilities – although, so far, there is precious little information about the new tool, Flex, and exactly what “composition over inheritance” will mean in practice.
One similar solution that this reminds me strongly of is Django, and its approach to “apps” – although this isn’t necessarily highlighted, a composition-type system ships with Django and comes with a number of both positive and negative implications.
Personally, I really like the forward advice that is being published about Symfony, although obviously it would be great to have a little more idea about plans right now. But let’s compare to how things work in Django.
First, a few words about Django apps. Although similarly MVC in style, Django-using code comes with a lot less boilerplate than most Symfony-using code. In fact, you generally only have two or three files – some information about routing, some code for your models (assuming you have/need them), some views. An app therefore can be very simple, but can also be quite complex, with large numbers of routes/views, complex business logic and models, huge amounts of template and UI.
In Django-speak your top-level directory is a project, and you create apps beneath that – directly writing/installing the app, or simply making it available as a dependency (Django projects tend to use pip to manage dependencies, much like composer).
Ideally, Django applications are reusable, but the actual footprint of an app is pretty negotiable. An application would be some substantial piece of functionality or something as simple as user management; but they also use a simple form of inheritance, so an app could be even less – it could even just be a theme.
“Installing” an application is as simple as making it available and then adding it to INSTALLED_APPLICATIONS – which is a simple list of application, so ordering is actually important here too.
So, if what is happening in Symfony 4 is going to look similar, what is it going to look like?
Given that Flex will be available for Symfony 3.3 – which is around the corner as I type – creation of a basic app which includes my pre-existing user management API might look a bit like this:
composer require symfony/flex
composer require my-apps/user-management --route=/apps/user
At a basic level, I need to be able to create an empty composer.json, bring in Symfony, and then tell it to add my app – and really, all I should need to give it (to begin with, at least) is the route under which I want the app to work. It may not be the case that you’d want to segment your routes by application per se, but at least to begin with you probably want some sensible defaults.
Given I have a user management app here, what kind of interfaces am I going to have? Well, I likely need to be able to interface to some kind of store – possible a database, maybe a directory – and my main app is definitely going to need to access either a user API or actual pages to perform authentication. So I likely have some routes for either or both of these things.
From the perspective of routes, the existing support for named routes (albeit perhaps namespaced?) is enough. But, in order to have a flexible user model I likely need to provide a service within DI that matches up to some interface that the application expects. If it’s anything like Django, I have some pages to log users in and out, register them in the first place, do password management tasks, etc. – so some kind of convention around templates is also important.
Of course, it is possible to manage hierarchies of templates using Twig inheritance. It would be quite strange to compose the applications and rely on inheritances to draw templates together, though. That said, it is an awful lot easier to imagine composing together a REST API than it is a login page – at least, without a great deal more opinion within Symfony by default.
In what circumstances are we going to be interested in using composition? Well, I definitely see the “small change to existing application” use case – using composition to create functional applications plus a theme works pretty well in Django, although you need a lot of convention to make it work well.
I also see that there is a lot of mileage is getting rid of application boilerplate. Login/authentication/user management makes sense as a standalone app, and just being able to bring in a useful application to kickstart the process like that is very useful. Composition only works well where the interface is pretty clean and simple, though – leaky abstractions can be a problem, and finding the right division between apps in general can be an issue.
However, in the Django world, I think this is where things get a lot less rosy. Community repositories of useful applications haven’t really taken off – Pinax is a great example of one, and its success has been pretty limited. I think this is for a number of reasons; finding the right level of abstraction is definitely tough, and to be honest Django probably isn’t strongly opinionated at a level that matters here. Getting sensible routes setup is pretty easy, for example – you have a set of URIs, perhaps some variables to interpolate, and a set of names, but it’s all exactly the same for each application you’d write.
On the other hand, though, interacting with an administrative back office is potentially an awful lot more complex – any API that allows an arbitrary object to be understood and interacted with in a back office application is going to be sophisticated and potentially difficult to implement.
It will be very interesting to see what route is taken by Symfony here. If the concept of an application is constrained to begin with, with some very simple interfaces and clear opinions about how and why you use them, this could be a very valuable addition to the arsenal. If, however, they arrive as a way of having applications automatically plugged together but little else, we’ll have a bit of a wild west of apps – and if the “wrong ones” get popular, a whole lot of bad practice will get baked in from the start.
I’m looking forward to seeing what the approach will be, though.