Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Messenger][DX] Allow stamps to be passed directly to MessageBusInterface::dispatch() #30707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 31, 2019

Conversation

weaverryan
Copy link
Member

@weaverryan weaverryan commented Mar 26, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? yes
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR TODO

Me again o/!

This proposal is purely for DX. With DelayStamp, the proposal of QueueNameStamp and future things like AmqpRoutingKeyStamp, stamps are becoming more common for end users to use. This changes how it looks to use them:

// before
$bus->dispatch(new Envelope(new SendSmsNotification('Hi!'), new DelayStamp(10), new QueueNameStamp('low')));

// after
$bus->dispatch(new SendSmsNotification('Hi!'), [new DelayStamp(10), new QueueNameStamp('low')]);

It's definitely a BC break, which is allowed because the component is experimental, though it should be minimized. This BC break shouldn't be felt by most end users, as creating your own bus is an advanced use-case. Even if you decorated it, you'll get an obvious error.

@weaverryan weaverryan requested a review from sroze as a code owner March 26, 2019 12:39
@carsonbot carsonbot added Status: Needs Review Messenger DX DX = Developer eXperience (anything that improves the experience of using Symfony) Feature BC Break labels Mar 26, 2019
@weaverryan weaverryan mentioned this pull request Mar 26, 2019
36 tasks
Copy link
Contributor

@ogizanagi ogizanagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The anonymous class implementing MessageBusInterface in src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php needs to be updated as well.

@sroze
Copy link
Contributor

sroze commented Mar 27, 2019

I find it confusing: my original assumption would have been that the other arguments are other messages, in case I want to dispatch multiple of them at the same time. I know it's been done this way on Envelope::__constructor but looking back, I'm not convinced.

This is much more explicit:

$bus->dispatch(
   new Envelope(new SendSmsNotification('Hi!'))
       ->with(new DelayStamp(10), new QueueNameStamp('low'))
);

Or if it's really important, let's make it an array so we identify easily that it should not be other messages?

$bus->dispatch(
   new SendSmsNotification('Hi!'),
   [ new DelayStamp(10), new QueueNameStamp('low') ]
);

@weaverryan weaverryan force-pushed the message-bus-envelopes-arg branch from a5d19c3 to 90c48c4 Compare March 27, 2019 12:02
@weaverryan
Copy link
Member Author

Hmm, fair point. Wrapping it in an array still looks great to me, and indeed, a bit more clear. I can change to use that if others agree.

@fabpot
Copy link
Member

fabpot commented Mar 27, 2019

I agree that using an array. looks a bit better.

@sroze
Copy link
Contributor

sroze commented Mar 27, 2019

I suggest we change the Envelope::__construct 2nd argument as well.

@weaverryan
Copy link
Member Author

This is ready to go:

  • 2nd arg added to MessageBusInterface: array $stamps = []
  • "2nd" arg on Envelope changed from StampInterface ...$stamps to array $stamps = []

@weaverryan weaverryan force-pushed the message-bus-envelopes-arg branch 2 times, most recently from 0b16b9a to a995c48 Compare March 28, 2019 04:09
@nicolas-grekas nicolas-grekas added this to the next milestone Mar 28, 2019
@weaverryan
Copy link
Member Author

Rebased & ready again

@fabpot
Copy link
Member

fabpot commented Mar 31, 2019

Thank you @weaverryan.

@fabpot fabpot merged commit e861de7 into symfony:master Mar 31, 2019
fabpot added a commit that referenced this pull request Mar 31, 2019
…MessageBusInterface::dispatch() (weaverryan)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[Messenger][DX] Allow stamps to be passed directly to MessageBusInterface::dispatch()

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | none
| License       | MIT
| Doc PR        | TODO

Me again o/!

This proposal is *purely* for DX. With `DelayStamp`, the proposal of QueueNameStamp and future things like `AmqpRoutingKeyStamp`, stamps are becoming more common for end users to use. This changes how it looks to use them:

```php
// before
$bus->dispatch(new Envelope(new SendSmsNotification('Hi!'), new DelayStamp(10), new QueueNameStamp('low')));

// after
$bus->dispatch(new SendSmsNotification('Hi!'), [new DelayStamp(10), new QueueNameStamp('low')]);
```

It's definitely a BC break, which is allowed because the component is experimental, though it should be minimized. This BC break shouldn't be felt by most end users, as creating your own bus is an advanced use-case. Even if you decorated it, you'll get an obvious error.

Commits
-------

e861de7 Allow stamps to be passed directly to MessageBusInterface::dispatch()
@sroze
Copy link
Contributor

sroze commented Mar 31, 2019

🤞 fixed failing tests in fd4146c.

@nicolas-grekas nicolas-grekas modified the milestones: next, 4.3 Apr 30, 2019
@fabpot fabpot mentioned this pull request May 9, 2019
@timiTao
Copy link
Contributor

timiTao commented May 9, 2019

@weaverryan I want to have clear bus interface, that clear purpose is to send a message. This configuration shows what message is sent and how it should be treated. Implementing this will force my class to 2 things - create the message and send them. MessageBusInterface is made more robust due to that.
This loses abstraction that Messenger was to give to the application - I should not concern about how the message is sent, but if it correctly accepted by bus and eventually delivered.

"preoccupied with whether or not they could, they didn't stop to think if they should."

I think the original way was showing the better purpose of this functionality. Now is a blurred.
I'm interested, your opinion about design this interface in the context of abstraction.

@weaverryan
Copy link
Member Author

Hi!

I don’t quite understand. We added an optional argument to the interface. Are you creating a class that implements this interface and the new argument causes you a problem? Or does the new optional argument cause an issue when you are using the interface?

Cheers!

@ro0NL
Copy link
Contributor

ro0NL commented May 9, 2019

if anything; we have 2 ways to do the same thing, as shown by the PR description. Not sure it's desired either 😕

currently messenger exposes a Stamp concept, which before was an implementation detail of the message.

As a vendor i might only care about "provide a message we can dispatch" (wether it's an envelope with stamps is a detail). But now the user might want to provide "a message" and "stamps", which as a vendor, i need to accept yes/no.

This is diversity happening :)

@weaverryan weaverryan deleted the message-bus-envelopes-arg branch May 9, 2019 13:06
@timiTao
Copy link
Contributor

timiTao commented May 9, 2019

@weaverryan
@ro0NL described this very good. I'm not talking about a technical problem, but design philosophy.
I think, enriching MessageBusInterface interface with the Stamp concept unnecessary add more details.
In my opinion, this improvement makes less explicit MessageBusInterface interface. Choices like that make the project depend on Messenger less supportable.

That is my opinion. To keep more to KISS rule ;)

For Stamps we have:

we have 2 ways to do the same thing

And for the general message, we have 3 ways to send it with Stamp:

message

$bus->dispatch(
   new SendSmsNotification('Hi!')
);

message + array stamps

$bus->dispatch(
   new SendSmsNotification('Hi!'),
   [new DelayStamp(10), new QueueNameStamp('low')]
);

envelope + array stamps

$bus->dispatch(
   new Envelope(new SendSmsNotification('Hi!')),
   [new DelayStamp(10), new QueueNameStamp('low')]
);

envelope with stamps

$bus->dispatch(
   new Envelope(new SendSmsNotification('Hi!'))
       ->with(new DelayStamp(10), new QueueNameStamp('low'))
);

@nicolas-grekas
Copy link
Member

Envelope has always been part of the "dispatch" contracts. Since StampInterface is an integral part of Envelope, stamps have always been part of the "dispatch" contracts too.
If there should only be one way, it could be to remove passing an Envelope directly.
But that would only create more WTF to me (e.g. pass an envelope and have it be considered the message?) + unneeded BC break maybe?

@ro0NL
Copy link
Contributor

ro0NL commented May 9, 2019

the nice thing is Envelope extends object, so we can see any message as type object, not knowing about evenelops/stamps.

I've no real issue with the change. Personally i like dispatch(object $message): Envelope (one can discard the return value, considering it void), it's straightforward.

Comparing this to a real life scenario; can we pass a message/envelop and its stamps separate to a mail deliverer? Wouldnt they expect a stamped message/envelop instead?

@weaverryan
Copy link
Member Author

Comparing this to a real life scenario; can we pass a message/envelop and its stamps separate to a mail deliverer? Wouldnt they expect a stamped message/envelop instead?

Ha! Indeed. But what I would personally really like is for the mail deliverer to come to my house, put the items in the envelope for me, close it, put the stamps on, then take it to the post office. That's a bit outside of the scope of what their job should be perhaps, but it would be awesome! Even in the real world scenario, there's a balance between purity and having a great customer experience (neither should dominate).

@timiTao
Copy link
Contributor

timiTao commented May 9, 2019

I really like your example, but I see this very straightforward.

For a simple message:

I would personally really like is for the mail deliverer to come to my house, put the items in the 
envelope for me, close it, put the stamps on, then take it to the post office.

you have:

$bus->dispatch(
   new SendSmsNotification('Hi!')
);

If you want advanced use, then you simply use Envelope with Stamp's.

This change simply provides something between that is neither of these solutions and don't give use real advantage - only more blurred interface:

I would personally really like is for the mail deliverer to come to my house, put the items in the 
envelope for me, close it, then *maybe I will inform him about my stamps and he can add his stamps on*, then take it to the post office.

@nicolas-grekas I always like Messenger not to be strict and enforce own Interface over message. Then any part of Envelope should be also added to this interface? Then why not add a third optional parameter, to act like Envelope function withoutAll? I think functionality/manage of Stamp's should be closed only in Envelope.

I simply want to keep it simple stupid:

  • give us a message and we will deliver it,
  • give us Envelope with extra data and we will deliver it as you wish.

@ro0NL
Copy link
Contributor

ro0NL commented May 10, 2019

the mail deliverer to come to my house, put the items in the envelope for me, close it, put the stamps on, then take it to the post office. That's a bit outside of the scope of what their job should be perhaps

exactly, it shows multiple concerns. Not an issue per se, but has its cost. In real life this is called Franking.

This also comes with a trust issue, some trust this to go right, others dont and stamp themselves. Hence i think this leads to diversity.

The question is; if we pass an "envelop/message" and "stamps" separate, can we assume it will be franked implicitly? Im not sure it's obvious.

Ultimately i believe a message should be stamped before it can be dispatched :/

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 10, 2019

Honestly, I lost track of what is discussed here.
If we're discussing variadic vs array as trailing argument, both are essentially the same and it's a matter of code style preference.

@ro0NL
Copy link
Contributor

ro0NL commented May 10, 2019

the "design philosophy" itself still :) (moving the stamping concern to the dispatching side)

@nicolas-grekas
Copy link
Member

it always has been on the dispatching side, so this is old :)

@ro0NL
Copy link
Contributor

ro0NL commented May 10, 2019

before we didnt stamp in dispatch() at least

-        $envelope = $message instanceof Envelope ? $message : new Envelope($message);
+        $envelope = Envelope::wrap($message, $stamps);

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 10, 2019

Semantically, this is strictly the same. There is a bijection between both styles:

$bus->dispatch($msg, $stamps);
vs
$bus->dispatch(new Envelope($msg, $stamps));

I see why the 1st style has been added. There is no technical reason not to do it.

* @param object|Envelope $message
* @param StampInterface[] $stamps
*/
public static function wrap($message, array $stamps = []): self
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weaverryan wouldnt stamp() be the better name? In case of explicit public usage ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to clarify; if wrapping means "put it in an envelop" this method doesnt always "wrap", whereas new Envelope($anything) does.

This method wraps if needed, but always stamps.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, are you suggesting a change? Or is it clear for you now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It stamps only if stamps are provided.
The main use case is removing the "if" that the method contains from userland boilerplate.
Tldr, wrap() fits my mind :)

Copy link
Contributor

@ro0NL ro0NL May 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it might fit; "we wrap it with stamps" :/ but to me that's "stamping", not "wrapping" (stamping requires an envelope wrap)

Just curious if wrap() and __construct() could be considered confusing...

Copy link
Contributor

@ro0NL ro0NL May 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It stamps only if stamps are provided.

hm indeed, missed this detail :} OK. these technical details are hard to convey with naming :) let's keep as is 👍

@timiTao
Copy link
Contributor

timiTao commented May 13, 2019

@nicolas-grekas
I simply wanted to show that the author took the direction that in my opinion, give more bad that good outcome.

If you insist that they are the only use cases, then that you are correct. This would be correct. The original:

$bus->dispatch($msg);

and

$bus->dispatch(new Envelope($msg, $stamps));

Semantically, this is strictly the not same. This led to ignoring the first use case. As mentioned here, I gave you my arguments. Is there any argument, that could convince you? Maybe, but not mine. If my arguments didn't convince you, my job here is done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BC Break DX DX = Developer eXperience (anything that improves the experience of using Symfony) Feature Messenger Status: Reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants