Hi Michael,

Thanks for your response. I have read about, and personally discussed the 
SOLID principles with Uncle Bob, and I do believe that there is more than 
one final interpretation of those principles. I can see your points, but 
raise you this:

SRP says only that a `car` class should not implement both responsibilities *by 
> itself*!


Currently, the middleware proposal and current used implementation ask for 
exactly that. That the middleware be responsible for the inbound and 
outbound flow. Even if it is for the middleware to decide that for itself, 
it is still a breach of SRP allowing a class to decide that. My point is 
the choice should not be there in the first place, by way of defined 
interfaces.

My point about ISP is to follow the definition you stated. If we take away 
the choice of multiple responsibilities from the middleware, then we must 
separate the interfaces. And I do know that it is not about PHP interfaces, 
but that is what they are for, along with the same in JAVA, and class 
abstractions; they are used to define the contract between classes: Can 
this middleware affect the request? Can this middleware affect the 
response? That kind of question comes from the interface the class 
implements.

Should some of your proposed interfaces be added to PSR-15?


Granted on that one, I did not realise about PSR-17.

On Sunday, 19 February 2017 19:11:22 UTC, Michael Mayer wrote:
>
> Hi John,
>
> many thanks for your contribution. But as far as I can see, there is a big 
> misconceptions about single responsibility principle (SRP) 
> <https://en.wikipedia.org/wiki/Single_responsibility_principle> and interface 
> segregation principle (ISP) 
> <https://en.wikipedia.org/wiki/Interface_segregation_principle>.
>
> At first SRP; Robert C. Martin expresses the principle as follows:
>
> A class should have only one reason to change.
>
>
> SRP is NOT about objects, it is about classes. Objects are usually 
> always(!) responsible for many things, for example a `car` object is 
> responsible for the acceleration and the honking. SRP says only that a 
> `car` class should not implement both responsibilities *by itself*! There 
> are many ways we can have SRP in the car example. Delegation, inheritance 
> and partial classes (traits) are the most common ones (e.g. wikipedia 
> presents an example of SoC and partial classes 
> <https://en.wikipedia.org/wiki/Separation_of_concerns#SoC_via_partial_classes>,
>  
> which is also an example for SRP).
>
>
> Second, about your ISP considerations. Sorry, I cannot fully follow you on 
> this. ISP is about:
>
>> The interface-segregation principle (ISP) states that no client should 
>> be forced to depend on methods it does not use. [Wikipedia]
>
>
> The current `MiddlewareInterface::process(ServerRequestInterface $request, 
> DelegateInterface $delegate)` is fully dedicated to the situation, when you 
> need both: the request and a way to delegate requests. If you do not need 
> both, then `MiddlewareInterface` is the wrong interface for your use case. 
> And please note: the current PSR does not force you to use it in that 
> cases. It just do not provide some additionally useful interfaces. – Should 
> some of your proposed interfaces be added to PSR-15? I believe not, for 
> example your `ResponseFactoryInterface` has nothing to do with *Middle*wares, 
> the interfaces instances does not sit in the *middle* of some input and 
> output. Hence, I believe it is fine to have it in PSR-17.
>
> Btw, ISP is NOT about the PHP `interface` feature! Robert C. Martin uses 
> the word *interface *in the same sense as in *graphical user interface*, 
> *command 
> line interface* or *network interface –* in the same meaning as *protocol* 
> or *contract*. You may want to read his blog entry 'Interface' Considered 
> Harmful 
> <http://blog.cleancoder.com/uncle-bob/2015/01/08/InterfaceConsideredHarmful.html>
>  about 
> the language feature.
>
> Having said all that, thank you again for your thoughts – I share many of 
> your concerns, but IMO most problems are not related the PHP 
> `interfaces`, but to the contracts. For example 
> `MiddlewareInterface::process` 
> <https://github.com/http-interop/http-middleware/blob/bc7b35ddab0f376d9bb832232dbe4cfc1417a538/src/MiddlewareInterface.php#L11-L12>
> :
> > * delegating to the next middleware component
>
> Damn it! Why must a Middleware know, that other middlewares may be 
> present? Is a Middleware responsible for the next one too???
>
> Bests, Michael
>
> Am Sonntag, 19. Februar 2017 15:48:02 UTC+1 schrieb John Porter:
>
>> I've re-read everything that was discussed in my last issue #46 
>> <https://github.com/http-interop/http-middleware/issues/46> and I 
>> realise that having an example of an alternative that fixes my myriad of 
>> concerns over swapping one flawed implementation for another (no offence 
>> meant), is preferable over me just offloading my confusing concerns.
>>
>>
>> I can clearly see my previous issue asked one question, then rambled 
>> about other aspects of my concerns, so in an attempt to separate concerns 
>> (see what I did there?) I will focus on a single response to this proposal.
>>
>>
>> An Alternative Approach to Middleware
>>
>> I can see why a single pass approach is preferable to the double pass, 
>> but in my mind, they are still both flawed and violate the single 
>> responsibility principle and also the interface segregation principle.
>>
>>
>> In both cases, the middleware is allowed to know too much about the 
>> entire process of accepting a request, and expecting a response; whether 
>> that be the double pass having a pre baked response instance, or the single 
>> pass being told about the 'next' item in the chain.
>>
>> A Middleware should only care about what it is supposed to do in the 
>> simplest way possible, enforcing the SRP.
>>
>>
>> I am proposing that we really look at what the requirement is here, and 
>> come up with something that fits the bill properly, rather than rehash 
>> previous principles that smell bad. Here is something I started to touch on 
>> in my issue, and that @schnittstabil <https://github.com/schnittstabil> has 
>> also touched on.
>>
>>
>> <?phpnamespace Psr\Http\Middleware;use 
>> Psr\Http\Message\ResponseInterface;interface MiddlewareInterface{}
>>
>>
>> We need a base interface that can allow type hinting a single point of 
>> adding middleware to a queue for example.
>>
>>
>> <?phpnamespace Psr\Http\Middleware;use 
>> Psr\Http\Message\ResponseInterface;interface ResponseFactoryInterface{    
>> public function createResponseInstance(): ResponseInterface;}
>>
>>
>> We need an interface to allow implementers access to a factory method to 
>> provide whatever implementation of a ResponseInterface is desired for 
>> that Middleware.
>>
>>
>> <?phpnamespace Psr\Http\Middleware;use Psr\Http\Message\MessageInterface;use 
>> Psr\Http\Message\RequestInterface;interface RequestMiddlewareInterface 
>> extends MiddlewareInterface{    public function 
>> parseRequest(RequestInterface $request): MessageInterface;}
>>
>>
>> We have an interface that provides Middleware for the inbound flow of a 
>> stack. Also note that to allow the Middleware stack to be short circuited, 
>> we only type hint a response to be MessageInterface. This means, normal 
>> behaviour for the stack is to proceed on a returned instance of 
>> RequestInterface, and if an instance of ResponseInterface is given, stop 
>> the inbound run of the stack.
>>
>>
>> <?phpnamespace Psr\Http\Middleware;use 
>> Psr\Http\Message\ResponseInterface;interface ResponseMiddlewareInterface 
>> extends MiddlewareInterface{    public function 
>> parseResponse(ResponseInterface $response): ResponseInterface;}
>>
>>
>> We have an interface that provides middleware for outbound flow of the 
>> stack. This allows us to have middleware that can, for example, change the 
>> cache headers of the response based on business rules.
>>
>>
>> <?phpnamespace Psr\Http;use Psr\Http\Message\RequestInterface;use 
>> Psr\Http\Message\ResponseInterface;interface ExchangeInterface{    public 
>> function exchange(RequestInterface $request): ResponseInterface;}
>>
>>
>> We should also be opinionated on how a request is exchanged with a 
>> response, even if only to say "Hey I give you a request, you give me a 
>> response!". This would lie a level above in the namespace of course, being 
>> that it is not specific to messages or middleware.
>>
>>
>> Why Another Proposal
>>
>>
>> I can picture faces of interest and faces of concern over this idea. Let 
>> me explain some more detail.
>>
>> We are violating the SRP and ISP in both implementations thus far, and we 
>> need to reimagine this as above to prevent that violation. Let me write the 
>> middleware use cases I've seen so far:
>>
>>    1. I want to make a Middleware to handle requests.
>>    2. I want to make a Middleware to alter a response.
>>    3. I need to make an instance of a response to short circuit the 
>>    exchange.
>>
>> These are fundamentally three separate responsibilities, and must be 
>> separated. There is no valid argument against this, sorry to annoy anyone 
>> there, but that's the truth. To fix this from both current implementations, 
>> we segregate the interfaces, therefore separating the concerns.
>>
>>
>> Add to the above the fact we let the Middleware itself choose whether to 
>> continue the stack or not, by providing a callback in the form of 'next', 
>> we have a messy situation that needs cleaning up.
>>
>>
>> Why do we allow a Middleware to handle both inbound and outbound flow in 
>> one function, and also pass in a hook to the outside world? That hook, if 
>> implemented badly could allow a Middleware to cause all sorts of havoc by 
>> accessing things it should never know about!
>>
>>
>> No, let us be strict here and not let the Middleware know anything about 
>> the outside world, other than the request/response (dependent on interface) 
>> and it's single responsibility.
>>
>>
>> Benefits of the above proposal
>>
>>
>> There are the obvious ones being separation of concern and interface 
>> segregation, I think I've covered those.
>>
>>    - The Middleware stack becomes the only place that can control the 
>>    continued iteration of the stack, not the Middleware.
>>    - A Middleware can still be responsible for both inbound and outbound 
>>    flow, by implementing both interfaces (although this is not the proper 
>>    thing to do).
>>    - A Middleware can still short circuit the stack by returning a 
>>    response, which still lies within SRP being that we only require a 
>>    MessageInterface instance.
>>    - A Middleware stack can become responsible alone for making a 
>>    response instance by implementing the factory method. This is also still 
>>    within the SRP as it is there to exchange a request for a response. 
>> (Let's 
>>    not argue about iteration and factory being two responsibilities, they 
>>    aren't in this case.)
>>
>> Also, please take note that I have specifically not used 
>> ServerRequestInterface. There is no reason at all that this 
>> implementation would not function in a client middleware environment also. 
>> Why repeat things by waiting for a client middleware proposal when one will 
>> do?
>>
>> Wrap Up
>>
>>
>> As I've said before, this is no insult to anyone who has put work in so 
>> far, I am just coming at this from a fresh perspective. Please discuss this 
>> as I fear for this being finalised as another incorrect design that will be 
>> around for years to come; I never liked the double pass, and I don't like 
>> the single pass either. Something better is needed.
>>
>

-- 
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 php-fig+unsubscr...@googlegroups.com.
To post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/acec8e69-8884-4b1c-b264-2136d4ee1a01%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to