Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Forked from anonymous/dispatcher_assessment.md
Last active August 29, 2015 14:20
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save JoshCheek/89e690f26ee0948e0110 to your computer and use it in GitHub Desktop.

Looked at the winning Dispatcher. Yours is better, b/c you can take it all by itself. Here are some examples of totally reasonable requirements that would feasibly be required of this application, in the real world. The winning one can't handle them without a refactoring like what we did:

Speed up the algorithm

Turns the app is handling more of these than we expected, the and it's not fast enough, taking several seconds in some cases, to find a solution. In our case, we make one query, and do one save, the algorithm itself just iterates over a few arrays, so it scales up very nicely. The "winning" solution performs a query for each type, so once we have 100 types, that dispatcher class must perform 100 queries for every emergency. They also save every time they add a responder, so an emergency with 50 responders will have 50 saves. It is very difficult to look at and identify what other operations will require talking to the database, but talking to the database is sufficiently expensive, that this dependency will almost certainly lead to multi-second response times as the app scales up.

Add a simulation endpoint

So someone can say "what would it look like if I submitted this emergency?" ie to show the user a preview before they click "submit". Winning solution can't handle this, because determining who to dispatch is coupled to the act of dispatching.

Human oversight

For any "ties", present the options to the user, who will select which dispatch to go with. Their solution can't do this, for the same reason as given above.

Add Interns

Interns need to store data in their table that deals with their studies. All interns can be called upon to respond to an emergency, though. But as they are only minimally trained, and might be studying a different type, they only have a capacity of one. The current dispatcher can't handle this, because it is coupled to the Responder table in the database, but now it would need two types. Your code can almost handle it, it would only need to push the @responders.select { |r| r.type == type } down into the responder. We would probably switch that to be something like @responders.select { |r| r.handles? type }. We might promote our mocks to real objects, used by our code, and have the controller convert both Interns and Responders into what we currently call Mock::Responder.

Allow arbitrary emergency types

Both pieces of code would need to change for this requirement, ours currently contains the set in Dispatcher#force_branches, and theirs is in Responder.types. In both cases, we'd probably need to move this onto the emergency.

Additional help from neighboring responders

Say we can query a handful of different APIs to call on other services for additional responders. They provide clients for us, but each one has a different interface. In our example, Dispatcher remains unchanged, it is the caller's responsibility to get the responders for us. Thus it probably creates an object whose job is to get all the responders from all the apis, and convert them into our Mock::Responder objects, thus unifying the interface. The winning solution, will either have to make the refactorings we did, or will have to embed API querying into the middle of its algorithm. And when it gets the three different types of responders back, how will it deal with them? It will either need if statements in multiple places, to ask for or calculate their capacity, depending on which remote api it found them in, or it will have to translate them into its own Responder objects. But its responder objects are tied to its database, and it can't add them to the emergency without causing them to be saved into the database, even though they aren't our app's responders. Furthermore, how will it then request the responder from the remote api? The winning algorithm is utterly unable to handle a requirement like this, while ours requires no change to the dispatcher algorithm. The algorithm is agnostic to where we got the responders, or what we are going to do with them.

Add logging

We want to be able to see which responders handled the most emergencies, and which ones could have handled an emergency, but weren't assigned. This will cause changes to the schema, and require recording of additional information. The winning dispatcher solution will need to be altered to accommodate the schema changes, and to track and add logging for the unassigned responders. For us, all this information is known in the controller method that initiated the dispatcher algorithm. We only need to change this one place, and the algorithm remains unaffected by the schema change, and the logging requirements.

Determine the best algorithm

we have an optimization that we think will lead to better assigning of responders. One way we can determine if it is better is to take the list of emergencies and availability of the responders over the last 6 months, and run both sets of data against the algorithms to see if we were able to apply a full response to more emergencies. Our algorithm only requires a "runner", a piece of code to iterate over the list of emergencies we saw, feed them into the algorithm, and then track how that affects the situation. It will likely complete in under a second, and requires no changes to the algorithm. We can trivially run it against our prod database, or dump the prod data to JSON or CSV, and then run against this data. We don't need Rails, only the one file with the algorithm and the integration code that sits above it. The winning algorithm will need to export all the events from the database into a new database, and then load ActiveRecord (and thousands of lines of code from its dependencies, like ActiveSupport), it could conceivably take an hour, because the cost of talking to the database is very high. It may need to have an "import" strategy, where it must make the database look correct according to the moment in time that the algorithm would have run. Each run through the algorithm requires the database be reset to its initial configuration, because checking the algorithm against the data modifies the database.

Staffing suggestions

Similar idea to the above, with all the same answers for all the same reasons: Too many emergencies have not had full responses. The director comes to you and says "We're thinking about hiring Rhonda Respondalot, a top notch responder, who has a capacity of 30 for fire emergencies. Would that get 90% of emergencies to have a full response?"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment