I'm in the process of building a bot and the experience has been challenging for me so far. This is most likely since I'm coming from v1 and I'm trying to rebuild my bot in v4 style, which is pretty much a completely different framework it seems.
I find there's quite a lot of documentation out there, but it's been split up into theory and practice, probably due to the different development frameworks you can use (i.e. Node, C#). But having to go back and forth between these articles is not helping,
After quite a bit of messing around, I got to a point where things are beginning to get a bit more decent, but I still feel there's lots of room for improvement. I can't share the whole project at the moment, but I've created a gist of the most important code here: https://gist.github.com/jsiegmund/831d5337b1a438133991070daba8a27e
So my issues/questions with this code are the following:
The way to add dialogs and mainly the need to add prompts for retrieving the answers is confusing. I get the idea, but not the inner workings. For instance: I now have the prompts named after the same method names of the corresponding dialog step, is that the way it's supposed to work? There seems to be some magic code linking everything together, by convention? It would make much more sense to me when the waterfall steps would also include the prompts.
What's the right way of feeding the dialog with information so it can skip steps? I've got LUIS intents set-up in the main dialog which then open up this dialog for hour booking. Suppose my user says "I'd like to book 8 hours on customer X", I'd like the dialog to pre-populate the amount to 8 and the customer to X.
The customer/project resolving is maybe a not-so-standard requirement here. These come from a third party application, retrieved through API/SDK. So based on the logged-in user I need to go out to that application and retrieve the data for this user. This comes back in key/value pairs, where the key is a GUID. I don't want the user to type in GUIDs, so I have created these action buttons with the names of the customers, but to get the ID value into the next step it now 'writes' the GUID in the chat instead of the customer name. Using the name is tricky as I can't fully rely on those being unique. Also, for selecting the project I need the customer GUID and saving the final entry I also need the ID's. But I don't want the user to see those.
The way I now have the cards built is also weird to me. I first need to add a dialog for the card, and later when calling stepContext.PromptAsync I need to supply the card as an attachment as well. Feels duplicate to me, but removing either one of the steps fails. The normal style prompt doesn't work for me as that doesn't handle key/value but just strings (see number 3).
Okay, so those are some of the things I'm struggling with. I'm getting there and it works for now, but as said I can't escape the feeling that I'm not doing it right. If anyone could shine a light on this that would be highly appreciated.
Yeah, there is a lot of changes from version to version. Do you really mean v1?! 😲 Or v3?
The way to add dialogs and mainly the need to add prompts for retrieving the answers is confusing. I get the idea, but not really
the inner workings. For instance: I now have the prompts named after
the same method names of the corresponding dialog step, is that the
way it's supposed to work? There seems to be some magic code linking
everything together, by convention? It would make much more sense to
me when the waterfall steps would also include the prompts.
Essentially. The steps listed in the waterfall array are the names of the method names you've created. Basically, this is where you are giving the order of the steps that should be done by the bot. Prompts are classes used to retrieve data and are populated into the ("main") dialog using AddDialog() and are stored in dialog state with unique names so that they can be retrieved correctly. I see your point on how it might be simple to have everything setup in one "call" or declaration, and there probably could have been other approaches to how this was implemented; but this is what we got.
What's the right way of feeding the dialog with information so it can skip steps? I've got LUIS intents set-up in a main dialog which
then open up this dialog for hour booking. Suppose my user says "I'd
like to book 8 hours on customer X", I'd like the dialog to
pre-populate the amount to 8 and the customer to X.
Typically, steps use the previous steps value to reply, act or continue. In simple scenarios, skipping steps can be done by checking the state for those values. In the multiturn sample, if the user does not want to supply their age, it goes on to the next step and then it checks for the value and skips the step (it really doesn't skip it, it reports no age given, but you could just continue without any reply). Assuming the LUIS side of things is correct and getting the right intent+entities (let's say 'booking' intent and entities ['time' and 'customer']), then that should be doable. You would populate state info for both of those entities and then the later step (say prompting for the customer step) would just skip/bypass.
But, what you really want to do is look at adaptive dialogs. They are new and make this type of scenarios much more dynamic and flexible. Look here:
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-adaptive-dialog-introduction?view=azure-bot-service-4.0
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-dialogs-adaptive?view=azure-bot-service-4.0&tabs=csharp
https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/csharp_dotnetcore/adaptive-dialog
The customer / project resolving is maybe a not-so-standard requirement here. These come from a third party application, retrieved
through API/SDK. So based on the logged in user I need to go out to
that application and retrieve the data for this user. This comes back
in key/value pairs, where the key is a GUID. Obviously I don't want
the user to type in GUIDs, so I have created these action buttons with
the names of the customers, but to get the ID value into the next step
it now 'writes' the GUID in the chat instead of the customer name.
Using the name is tricky as I can't fully rely on those being unique.
I'm not 100% sure on this part. Let me look into it and get back to you.
Also, for selecting the project I need the customer GUID and saving
the final entry I also need the ID's. But I don't want the user to see
those.
State (conversation|user|etc) would be a good place to manage this.
The way I now have the cards built is also weird to me. I first need to add a dialog for the card, and later when calling
stepContext.PromptAsync I need to supply the card as an attachment as
well. Feels duplicate to me, but removing either one of the steps ends
in failure. The normal style prompt doesn't work for me as that
doesn't handle key/value but just strings (see number 3).
Nope, that's correct. I know it feels weird, but that is the way to do it. Basically, anything but simple text will be an attachment. Cards are JSON, therefore an attachment and you need to send that to the user/client.
You're doing it all correct. Again; I would suggest on looking at adaptive dialogs as that's the newer tech and the move forward. But otherwise; you're on the right path!
Related
I would like to test our new code without incurring the wrath of google, but the documentation from google leaves much to be desired...
A former employee used to use the GShoppingContent.php library, however it doesn't support the version 2 api.
so now I need to learn the api...
https://support.google.com/merchants/answer/188494
seems to indicate that our use of the mpn field is fine as it is a considered a unique identifier.
However it also says that the id is required, which as far as the code suggests, has never been set... as GShoppingContent has NO setProductId or setId function for the products, we have only ever used mpn, so I'll assume that this is a new requirement...
Also https://developers.google.com/shopping-content/v2/reference/v2/inventory/custombatch makes no reference to the possibility of using mpn or any other unique id that they offer...
Where might I find a list of REQUIRED changes? (including for example the use of the id attribute...)
If product id is not required for inventory updates, then where is the accurate and complete documentation for the batch inventory method?
As an alternative is there a way to test our new code with out getting banned by google for incorrect product data... (when we have done changes in the past it has resulted in being almost banned, even for the smallest of issues...)
Can't be certain, but it seems GShoppingContent sets the id to online:en:US:*SKU*
where *SKU* is what was passed into GSC_Product::setSKU.
Managed to learn this by OAuthing on https://developers.google.com/shopping-content/v2/reference/v2/products/list
they have a dry-run option so I felt safe running this without worry of damaging our product data, even temporarily. (plus list doesn't sound very likely to cause data corruption, but you never know...)
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
I'm starting a new project from scratch and have written User Stores to describe how a given user will interact with the system. But, I'm having trouble understanding how to break the first user story in to tasks without the first one becoming an epic.
For example, if I were building a car and the first user story said something like "As a driver, I would like to be able to change the direction of motion so that I don't hit things.", that would imply a user interface (steering wheel), but also motion (wheels) and everything necessary to link those together (axle, frame, linkage, etc...). In the end, that first user story always seems to represent about 40% of the project because it implies so much about the underlying architecture.
How do you break user stories down for a new project such that the first one doesn't become an epic representing your entire underlying architecture?
You might want to think of your story as a vertical slice of the system. A story may (and often will) touch components in all of the architectural layers of the system. You might therefore want to think of your tasks as the work needed to be done on each of the components that your story touches.
For example, Let's say you have a story like In order to easily be able to follow my friends' tweets, as a registered user, I want to automatically follow all of my gmail contacts that have twitter accounts.
In order to accomplish this, you will have to pass through the UI layer, service layer, persist some data in the data layer, and make an API call to twitter and gmail.
Your tasks might be:
Add an option to the menu
Add a new gmail authentication screen
Add a twitter authentication screen
Add a contact selection screen
Add a controller that calls into your service layer
Write a new service that does the work
Save contacts to the database
Modify your existing gmail API calling service to get contacts
Add a twitter API calling service to follow selected contacts
There: That's 9 possible tasks right there. Now, as a rule, you want your tasks to take roughly 1/2 a day to 2 days, with a bias towards one day (best practice, for sizing). Depending on the difficulty, you might break down these tasks further, or combine some if they are two easy (perhaps the two API calling services are so simple, you'd just have a modify external API services).
At any rate, this is a raw sketch of how to break the stories down.
EDIT:
In response to more question that I got on the subject of breaking stories into tasks, I wrote a blog post about it, and would like to share it here. I've elaborated on the steps needed to break the story. The link is here.
When we started projects under a Scrum management style, the first set of tasks was always broad, or as you describe it: epic. That's inevitable, the framework of any project is usually the most important, largest, and time-consuming portion, but it supports the rest of the project. In order to pare down the scale on overwhelming-ness of how much there is to do see if you can list the MOST essential parts. Then work on defining those tasks as the starting points. Therefore you have a few tasks as starting points for a broad beginning. Hope that makes sense!
A user story describe the what while a task is more about the how.
There is no perfect formula, just add any task that describe how the user story is going to be implemented, documented or tested.
Keep in mind that a task should be estimated in hours, so try to scale and detail the tasks accordingly.
If you feel that you have too many tasks for a story (even if you have 1-8 hours long tasks), then maybe you should consider rewriting your user story in the first place because it's probably too complex.
Good luck
The story that you implement at the beginning can be refined over time. You dont need to think that every story has to be the final version that the user is going to use.
For example, in a recent project we had to develop an application which involved indexing various websites, and matching them against filters created by users, and finally alerting the user of matches (thing of it as google alert on steroids).
If you look at it from one perspective, there is only one story - "As a user I want to get alerts from matching pages". But look at it from another perspective of "what are the risks we want to mitigate". The first risk was that users wouldn't get relevant or better hits compared to google alerts. The second risk was in learning the technology to build this.
So our first user story was simply "As a user I want relevant hits", then we built just the hit matching algorithm on a hardcoded set of pages and hardcoded filters for some early users and got their feedback.
There might actually be a bit of back and forth here with multiple smaller stories to capture learning like "As a user I want more priority to be given to matches in the URL" etc.. these stories comes from the feedback as we iterate over what the early users consider "relevant hits".
Next, we broadened it to "As a user I want hits from specific websites" and we built the indexing architecture to crawl user specified sites and do hit matching on that.
The third story was "As a user I want to define my own filters", and we built this part of the system.
In this way we were able to build up the architecture piece by piece. Through most of the initial part, only early users could use the system, and many pieces of data were hardcoded etc.
After a point, early users could use the system completely. Then we added stories for allowing new users to register and opened it up to the public.
To cut a long story short, the story you implement first could implement only a small part of the final story, hardcoding and scaffolding everything else. And then you can iterate on it over time till you get the story that you might actually release to the public.
I've come to a crossroads with this issue in the past. User stories are supposed to be isolated so you can do them without any other stories, in whatever order, etc. But I found making that happen just made everything more complicated. To me this fell under the "Individuals and interactions over processes and tools" part of the agile manifesto - or at least my interpretation of it.
The ultimate goal is ship. And to ship you have to build, and to build you have to stop futzing with scrum and just get stuff done and make sure you track it.
So what we did was break a cardinal rule of stories and we made some tech stories like "create a preliminary schema". We also declared that some stories were dependent on others, and noted that on the back of the story card.
In the end I felt this type of story was few and far between, and the difficulty of the alternative justified the exception.
I am creating a new entity in CRM 4.0 to track our projects. One field is a Project Code, and I'd like to have a way to ensure that this field contains a unique value.
I understand that this is not a key, and it won't be used as a key, but for human readability/tracking purposes, it would be nice if I could tell the user that the code he just entered has already been used.
I am thinking that a webservice/javascript call will be necessary, but I wanted to see if anyone else has tackled this issue already.
Depends on how foolproof you want it to be.
The web service call is pretty lightweight, but if two people save a record at the same time, it's not going to detect it at that time, and dupe codes will happen.
A custom plugin would definitely detect dupe codes, but you don't get any feedback until after the user attempts to save. There's also still a small chance there could be repeat codes from users entering records.
The completely bulletproof way we've used is to have a plugin that checks a custom database table that we lock and then only let one plugin at a time through.
I am developing a web application that collects data over multiple steps through a wizard. Steps are generally not interdependent, in that data input at each step has little or no effect on the consequent steps. However each step may have a set of validations which determine whether the user can progress to the next step by clicking 'continue'
What should be the behavior when the user clicks previous?
a> Quickly move to the previous page, thus losing all the unsaved data in the form. Prompting the user with a warning is an option, but it can become irritating quite soon.
b> Move to the previous page saving all the data in the current step - without triggering validations, so that when the user comes back she sees the form in the same state that she left it in.
c> any other behaviour
All opinions are welcome :)
You should save the entered data, but you can get away by saving it volatilely (clientside or in memory - cookies or SESSION). No need to make it persistent in your DB or anything - if the user doesn't complete the wizard entirily, there need not be a trace (though it would be nice, if you can afford the resources. Cookies should suffice though).
This reflects the user's Mental Model: most popular Windows installers work like this.
This conforms with DRY - Don't Repeat Yourself. If the user has already answered the question, don't make him re-answer.
The easy way to answer this is to remind yourself that the software exists to serve the user, not the other way around. The users job is not to fill in your form per se. That's just a means to some other end.
Do every automatic save you possibly can, remember as much as possible, and don't make the user do any more data entry than is strictly necessary.
And make sure you only validate really important stuff. Don't whine about "phone numbers can't have - in them!" and things like that. If you don't accept dashes, simply remove them and move on, don't make the user do it.
Remember: the software is there to serve the user, so when answering the question "should I ...?" always ask "how will my decision affect the user".
Agree with what Bryan said.
Btw, can't you explain everything (why you need that value, what happens if user enters that value/select that option) in the form so user don't have to go back to edit?
Of course you should save everything so user don't have to re-enter everything again, but it would be nice if you can give enough info to the user while filling the form so that he dont have to go back and forth while filling the form.
It happens sometimes that one feature seems to belong to more than one place.
Trivial example, let's say I've got the following menus :
File
Pending orders
Accepted orders
Tools
Help
I've got a search feature, and the same search window work for both pending and accepted orders (it's just an 'order status' combo you can change)
Where does this search feature belongs?
The Tools menu seems to be a good choice, but I'm afraid the users may expect the search accepted orders to be in the accepted orders menu, which would make sense
Duplicating the menu entry in both pending and accepted order seems wrong to me.
What would you do? (And let's pretend we cannot merge the two orders menu into one single menu)
I think the problem you've run into is that you're thinking like a programmer. (code duplication bad). I'm not faulting you for it, I do the same thing. Multiple paths to the same screen, or multiple ways to handle the same process can actually be extremely beneficial. I would guess that more than one person is going to use your program and each probably have slightly different job functions. In essence, they have different needs for the application and will approach using it different ways. If you stick to the all items have one way of being accessed, some people will find the application beneficial and others won't. Sure all people can learn to do a task a certain way, but it won't make sense to some users. It's not intuitive (read familiar) to they way they are used to processing information, which means the application will ultimately be less beneficial to them. When people find a process (program etc.) frustrating, they won't adopt it. They find reasons why the process will need to be changed or abandoned.
An excellent example of the multiple approaches to a problem is with Adobe Photoshop. Normally there are at least 2 different ways to access a function. Most users only know of one, because that's all they are concerned with, but most users are really comfortable with using one, because it makes the most sense to them. With a little extra work, Adobe scored a huge win, because more people find their product intuitive.
Having a feature in multiple locations is not a bad thing. Consider the overall workflow for viewing both pending orders and accepted orders, and think of your new feature as a component, rather than a one-off entity.
After you map out exactly what tasks a user completes in the pending and accepted order viewing process, see where having the ability to search would provide value (by shortening the workflow or otherwise). This is where your search component belongs.
The main thing to remember about UI is that all that really matters in the end is whether your design makes using your application or site a better experience for your users.
In the search example you list above you'll commonly see apps take two approaches:
Put the search feature in a single location and allow the user to filter the search by selecting pending or accepted, or
Put the search feature in both menus, already configured for the type of search to be done based on the menu it was launched from.
If you repeat the above choice for a number of factors you'll see a much more advanced (aka 'complicated') search interface for number one, and a much simpler (aka 'restrictive') search interface for number two.
Which one is best completely depends on your users. This is why many general applications have a simple search by default and a link to a more advanced search for those that want or need the additional capabilities; they're attempting to make everyone happy. There is absolutely nothing wrong with that if you're writing for a wide variety of people with different needs. If you're writing for a set of users with a restricted set of needs however, you can make some better choices.
In my experience your best bet is to work with one or two of your primary users and map out all of the steps they need to take to get each of the tasks the application will be helping them with accomplished. If there aren't a lot of branching points in that sequence of steps there shouldn't be a lot of choices or settings to make in the application; otherwise the users may feel that the app is harder to work with than it needs to be.
For the search example above, if the user has already navigated into the Pending Orders menu, the likelihood that they'll want to launch a search for Accepted Orders is very small and having to make that choice, or go elsewhere to do the search, will be an extra decision or action they'll need to take. Basic principle is if your user has already made a decision, use it; don't make them tell you again.
Use the UI you come up with as a first cut. Let your users, or a subset of them, try it out and make suggestions. If you have the option, watch them use it. You'll learn far more about how to improve the interface by seeing how they work with it than you will from what they tell you.
Generally you do not want the same menu item appearing in different menus. It adds complexity and clutter to the menu, and users will wonder if the two menu items are really the same or not. When it appears that a menu item belongs in two places, then you may have a more basic problem with your menu organization.
For instance, your example shows a menu bar that is organized by the class or attribute of the object the commands within act on. In general, the menu bar should be organized by category of action not type of object. For example, you could have a Retrieval menu for commands like Search and other means of displaying orders, and a Modify menu for processing the orders (e.g., updating, accepting, forwarding). Both menus would have menu items that apply to both types of objects, although some commands may apply to only one.
Organizing commands by object type is actually a good idea but it is better accomplished with a context menu (right click) than the menu bar.
I would try the search in both the Accepted Orders and Pending Orders menus. However, user testing will show if this is a good idea or not. But it also depends on your user base.
You are doing user testing right?
...you may already know this, but this is a good place to use the command\action pattern IMHO.
So to answer your question: IMO, yes, it is ok :) This situation is definitely warranted.
Just put it under both menus and have it open your search window, pre-configured for the order type who's menu it was launched from. Name them accordingly and voila they're actually two different actions - even though they use the same code/component.
Keep the user-selectable "status combo you can change" in the search window active though so the user still can adjust the settings without relaunching it from the other menu... and then perhaps rethink the structure, see some of the great answers in here for ideas ^^