Currently, we can create a sender from one method that has a queueOrTopicName parameter.
CreateSender(string queueOrTopicName).
We then have CreateReceiver/Processor methods that expect either a queue, or a combination of topic and subscription names. In UX studies, most users ended up supplying a topicName in the queueName overload, and not including the subscription. This is probably at least in part due to the asymmetry with the way the CreateSender method works (it takes either queue or topic in one param).
One idea would be to have Create(Subscription|Topic)Receiver/Processor methods instead of relying on overloads in CreateReceiver/Processor.
/cc @richardpark-msft @hemanttanwar @KieranBrantnerMagee
Why not introduce a dedicated value type struct for a queue and a topic to get rid of this ambiguity?
Interesting idea. Do you mean something like this:
```c#
public struct ServiceBusEntity
{
public string QueueName { get; set; }
public string TopicName { get; set; }
public string SubscriptionName { get; set; }
}
We would then be able to get rid of our overloads and have single method for CreateReceiver/Processor:
```c#
public ServiceBusReceiver CreateReceiver(ServiceBusEntity entity)
We would call it like:
c#
ServiceBusEntity entity = new ServiceBusEntity
{
TopicName = topicName,
SubscriptionName = subscriptionName
};
var receiver = client.CreateReceiver(entity);
This would allow us to perform validation so that if a user sets a TopicName without a SubscriptionName we could throw an ArgumentException.
I wish we had discriminated union in CSharp but yes something like that:
public readonly struct ServiceBusEntity
{
public ServiceBusEntity(string queueName)
{
TopicName = null;
SubscriptionName = null;
QueueName = queueName;
}
public ServiceBusEntity(string subscriptionName, string topicName)
{
TopicName = topicName;
SubscriptionName = subscriptionName;
QueueName = null;
}
public string QueueName { get; }
public string TopicName { get; }
public string SubscriptionName { get; }
}
If we expose the ctor params, then I would expect to still see the same sort of behavior where a user puts the topic name into the queueName parameter. By leaving as settable through properties only, we force them to be explicit. On the other hand, we would be introducing a new type for what should hopefully be an easily diagnosable mistake.
What about scenarios when the source (or the destination) is just a string rather than a type?
E.g., receiving from an entity that is either a queue or a subscription. Forcing users to create a strongly typed ServiceBusEntity will complicate this use case.
One idea would be to have Create(Subscription|Topic)Receiver/Processor methods instead of relying on overloads in CreateReceiver/Processor.
Just to point out, CreateTopicReceiver or CreateTopicProcessor would not be possible, @JoshLove-msft
In UX studies, most users ended up supplying a topicName in the queueName overload, and not including the subscription.
That's peculiar given that messages simply cannot be received from a topic. Which raises questions about the specific study.
One idea would be to have Create(Subscription|Topic)Receiver/Processor methods instead of relying on overloads in CreateReceiver/Processor.
Just to point out,
CreateTopicReceiverorCreateTopicProcessorwould not be possible, @JoshLove-msftIn UX studies, most users ended up supplying a topicName in the queueName overload, and not including the subscription.
That's peculiar given that messages simply cannot be received from a topic. Which raises questions about the specific study.
Yes, CreateTopicReceiver would still expect both a subscription and topic name. The idea was to include topic in the name to draw the user's attention there. In the study, when the participants put the topic in the queueName parameter, they got an exception that the messaging entity didn't exist, as the method they were using was expecting a queueName.
Yes, CreateTopicReceiver would still expect both a subscription and topic name.
I strongly recommend not to go this route. Messages cannot be received from a topic. Having the SDK suggesting this in a method name is going to be very misleading.
Yes, CreateTopicReceiver would still expect both a subscription and topic name.
I strongly recommend not to go this route. Messages cannot be received from a topic. Having the SDK suggesting this in a method name is going to be very misleading.
Another name being considered would be CreateSubscriptionReceiver.
Another name being considered would be CreateSubscriptionReceiver.
At that point var receiver = client.CreateReceiver(entity); where entity is a ServiceBusEntity value type is becoming more appealing. While it's not an entity path expressed with a string, at least it's a single receive method that can take a variety of entities that are constructed in what's supposed to be a more clear way (referring to https://github.com/Azure/azure-sdk-for-net/issues/11552#issuecomment-619144414).
I'm wondering if this is actually an area we can leave as-is. Even in TypeScript where we do have discriminated unions we just handle this as an overload, much like what you have.
My thoughts:
I also think some of the confusion was less about the overload and more about what topics and subscriptions _are_ - at least a few of the participants were very familiar with queues but less familiar with the actual concepts of topic and subscription.
I also think some of the confusion was less about the overload and more about what topics and subscriptions _are_ - at least a few of the participants were very familiar with queues but less familiar with the actual concepts of topic and subscription.
I concur with this observation.
Since I was not part of the study I can only talk about my experience with customers that do queueing and can also concur that anything that goes beyond queues can become complex for people to grasp because there is more moving parts and you have to come up with a reasonable Topology that fits your needs. All more than basic queuing
Closing this out as the consensus is that we will not be making any changes to the creation methods.
Most helpful comment
I'm wondering if this is actually an area we can leave as-is. Even in TypeScript where we do have discriminated unions we just handle this as an overload, much like what you have.
My thoughts:
I also think some of the confusion was less about the overload and more about what topics and subscriptions _are_ - at least a few of the participants were very familiar with queues but less familiar with the actual concepts of topic and subscription.