Having slept on it, I see that you have valid concerns to which I don't
have good solutions, at least not at this time.

However, it seems that all of those concerns stem from two fixed ideas:

1. Creating individual middleware components must happen on-the-fly,
possibly coupled to a DI container.

2. The composition of a middleware stack is somehow easier to understand or
work with when represented as a flat stack or list.

Neither of those ideas are fixed in my head, perhaps that's where our
perspectives differ.

I think we have very different ideas about what middleware can or should be
used for.

To me, it's a modular approach for classification and filtering of HTTP
requests - it's not a new kind of application framework.

The projects I've been building with middleware the past two years largely
consist of something like:

1. Error handler
2. Application dispatch (router, controller dispatch)
3. 404 page

In some cases, there's a middleware for caching etc. in there, or a logger
- so with that, I think the most I've ever used is 5 components.

I long since gave up on trying to put things like routing and
session-management in there as separate components from application
dispatch - the component I call application dispatch handles both routing,
sessions and a cookie abstraction.

If that sounds like a lot to put in a single component, it's not - we're
literally talking about 25 lines of (trivial) code: invoke the router,
create the session and cookie abstraction and inject them into a request
context (a DI container), create the controller, and run it.

Trying to spread those concerns across several components feels like "doing
the right thing", because separation of concerns, right?

But the more I thought about it, the more I found that this point of view
is actually contrived.

Classifying the request actually ends with the router - once the
path/method have been mapped to a controller, the request has been
classified, and we're ready to dispatch - we're out of the HTTP domain into
the application domain.

At that point, things like the cookie and session abstractions are
dependencies of my controllers - they're how I choose to model and
integrate with the HTTP domain on a high level.

There's no reason that needs to be middleware. It's contrived, and only
works because you put those middlewares in the correct order, so they can
communicate - which is to say, they're really acting as a single component,
they can't operate correctly in isolation (or out of order) and the
apparent separation is only skin deep.

Components like this one, for example, don't make sense to me:

https://github.com/middlewares/fast-route/blob/master/src/FastRoute.php

It's a vestigial router integration that doesn't actually route to anything
- it doesn't dispatch anything.

In fact, it doesn't really do anything - not directly - it only produces
side-effects, by injecting the result into attributes, which is a means of
communicating it's result to the component that is going to actually
dispatch the controller. Clearly one is a dependency of the other.

It's a clever way to hide your dependencies, but they're still there - only
hidden, and much harder to debug. What does that accomplish?

I mean, I get it, you want everything to be modular - you want things such
as different router implementations to "plug and play" so you can just
throw them on the stack and have them work.

But that's not really possible - it doesn't really work that way, and
implementing it as middleware doesn't change that fact, it just hides that
fact. You haven't managed to abstract from anything - the dependency of
some other component, on the result produced by this one, is still there,
you've only managed to hide that fact. It's throwing complexity after more
complexity - fighting fire with fire.

You don't get modularity - what you get is fragmentation.

I'm stomping on this particular case because it's a perfect example of what
I would call middleware abuse.

If you'd stop trying to do that, your typical application would have much
fewer middleware components.

It wouldn't matter (much) if you were creating the individual middleware
components on-the-fly or not.

Your application would bootstrap a single HTTP kernel (in a DI container)
composed of some number of proxies/decorators.

I think where we differ is, you want to actually build the application
itself out of middleware components? I think that's contrived. The DI
container and abstractions is a better way to structure the application
itself.

To me, middleware is just a better, more structured way to classify and
filter HTTP requests - it's a well-structured approach to building
front-controllers.

It's not a "framework" or "architecture" for applications - that's a
different layer.

To me, a simple transaction like "takes a request, returns a response"
perfectly describes a front-controller, which is all I need to do at this
layer.

I don't know, maybe I just have a very different idea of middleware from
most people :-)


On Fri, Apr 21, 2017 at 11:30 PM, Matthieu Napoli <[email protected]>
wrote:

> > This is Symfony's HttpKernelInterface and StackPHP and it has already
>> been discussed at length
>>
>> Same principle, yes, but what I recall being discussed at length was the
>> lambda-style vs double-pass aspect, which seems unrelated to this
>> discussion.
>>
>> I found one or two older threads on this subject, here's one:
>>
>> https://groups.google.com/d/msg/php-fig/Ew36Ng5EwXE/52dAzZAbAQAJ
>>
>> The discussion quickly turns to the other, at the time dominant subject
>> though.
>>
>
> OK I've started to re-read the mega-thread (https://groups.google.com/
> forum/#!topic/php-fig/vTtGxdIuBX8%5B101-125%5D - 7 pages long) but most
> of the debate was indeed about lambda-style/double-pass, and I'm clearly
> not masochistic enough to read all of it again ^^
>
> So yes maybe we should discuss that (to me it feels like "again" but maybe
> that's just me).
>
>
>> > I'm not sure why we are starting it all again?
>>
>> Are you're saying all of the concerns I described here have been
>> discussed and are all invalid?
>>
>> According to the PSR-15 meta:
>>
>> - "There are currently two common approaches to server middleware that
>> use HTTP Messages", single-pass and double-pass.
>>
>> - There's no mention of the fact that HttpKernelInterface doesn't have
>> the delegate in the interface.
>>
>> - The section on "Delegate Design" talks about the design of that
>> interface, but doesn't say why it exists in the first place.
>>
>> I recall there being lengthy discussions about how to name and describe
>> the delegate interface, but skimming back through the discussion threads
>> that are listed in the meta, it seems that the discussions all start from
>> the assumption that a middleware interface has the delegate argument.
>>
>
> So yes even if it was discussed or not, the fact that it lacks from the
> metadocument is a sign there is something to improve here.
>
> My 2 cents about the Stack approach:
>
> - AFAIK it didn't work. And it was not tried in some weekend project: it
> was built on Symfony's interfaces, so pretty solid stuff and it got a good
> chance for success. On the other hand PSR-7 middlewares were incompatible
> with most of the existing architectures at the time (incompatible with
> Symfony for example) and without a standard interface (rather a "callable"
> convention) and it worked out! So to me that's a clear sign.
> - it's harder to compose middlewares because they are all nested: the
> "pipe" pattern was a huge help IMO in spreading the concept
> - it's harder to write reusable middlewares because you need to
> standardize the constructor (see the Stack "convention" about the
> constructor which is less than ideal)
> - it's harder to wire in DI containers
> - lazy middlewares are doable but not as easy
>
> That's all I have on my mind right now. And we may or may not have
> discussed it before, but the PHP community has already tried it. That kind
> of middleware has existed for a long time, and right now what works and
> what's spreading is not that kind of middlewares. I believe that's because
> of good reasons and we should not ignore that and start all over again.
>
> Matthieu
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/
> topic/php-fig/B3jtdJA7-6w/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/
> msgid/php-fig/b8317921-172a-476c-9df7-5b47e1f089da%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/b8317921-172a-476c-9df7-5b47e1f089da%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/CADqTB_jGzbWQaAPY3kyUD-G-%2BJ9MDdMVJOj%3Dinx1Nmb%2BLE902A%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to