riboseinc / duty-scheduling-calendar

Open source, Duty Scheduling Calendar ("`DutyCal'")
2 stars 0 forks source link

JS interface between UI and Algorithm #2

Open ronaldtse opened 7 years ago

ronaldtse commented 7 years ago

For @Haris987 @easy-one: please discuss here to agree on the interface for the various algorithm inputs and outputs so we can separate out the work.

Haris987 commented 7 years ago

From algorithm side, input parameters are pretty simple and straight-forward as described in description of daily-scheduling-calendar. There are few options, it all depends how we will show the result. In algorithm we need following info:

  1. List of persons to assign duties to (algorithm do not really care about their names or anything else, so it can be array of numbers, like 1, 2, 3, etc ...)
  2. List of days to which to assign people (again, it is not important to algorithm any info about days, it is not important if it can be array of numbers like 1, 2, 3, 4, etc ...)
  3. For every person we need array of days which can be some dictionary where every person would have array of available (or probably better of unavailable days depending how users will be entering it)
  4. For every day we need number of scheduled duties for that day, so it can be some dictionary dayId=>numOfDuties
  5. Max number of iterations for algorithm

# Option 1: Create classes for Person and ScheduledDays and send array of Persons and array of ScheduledDays and maxNumOfIterrations to algorithm. class Person{ int personId; some unique id, probably best 1, 2, 3, 4, ... int[] availableDay; => list of ids of available days (or unavailable depending on way user is entering it) ... any other info you want to add for a person }

class ScheduledDays{ int id; => some unique id, probably best 1, 2, 3, 4, etc ... int numOfDuties; number of duties to assign for that day ... any other info you want to have for ScheduledDays }

# Option2: Send 5 parameters to algorithm: persons_array => list of ids of persons (list of integers 1, 2, 3, 4, ...) scheduled_days_array => list of ids of scheduled days (list of integers 1, 2, 3, 4 ...) availability_days => dictionary which have keys from persons_array and value for each key is list of available days for each person (days should be some of the days from scheduled_days_array) scheduled_days_duties => dictionary which have keys from scheduled_days_array and values some integer which defines number of duties for that day number_of_iterations => integer number

Response will be list of persons where every person have list of assigned duties. Assigned duty will be pair (x, y) where x is day id and y is duty slot for day x.

I am open (and fine with) any other suggestions as long as I get available data for algorithm. This is something out of head to start discussion.

ronaldtse commented 7 years ago

Thanks @Haris987 for elaborating this out.

Option 1 is definitely easier to understand and use.

For identifying a person it is preferred to use UUIDs. For scheduled days we could use the date as the unique ID. Technically each calendar day can be represented by an integer, so we could just represent scheduled days and available days as integers.

In addition, it might be easier if we availableDay is represented as a date range so it is easy to ask "is this person available for this date?

Haris987 commented 7 years ago

Totally agree, Option 1 would definitely be my choice too, and using UUIDs for persons and integers for dates is totally fine for me.

For available/unavailable days range is fine too, but if there is a lot of 1 day absences then it could be a lot of availability ranges, but I assume it is not so common case. It will probably happen that someone is not available because of vacation (which will be some longer period like 2-3 weeks) rather then a lot of 1 day breaks, so date range could be better choice here.

ronaldtse commented 7 years ago

In either case available dates is easy to convert date range to/from individual dates anyway 😉

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 number_of_iterations: my opinion is that algorithm working time also depends much on number of days and number of persons. If Ronald sets wrong "number_of_iterations" count, he can end up waiting for minutes or hours for algorithm to finish. On the other side, if he sets it too small, he will get results far from optimal, and he won't know how far the results are from "theoretically perfect" result.

It would be far more useful and user friendly to set "max_working_time" parameter instead. If it's possible, you can add "fairness_precision" or similar parameter. Or, you can tell how precise the result is at current iteration.

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 regarding days identification. I totally agree it's best to work with days as integers for you and me. The best idea that came to my head is to count the number of days since, for example, January 1st 2017.

On your side you operate with integers only, while on my side I can quickly convert date to integer and back.

I can work with both availability ranges and plain array of available days. You can choose which is best for you.

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 @ronaldtse regarding calculations, I've recently suggested a client-server application (instead of standalone javascript app which uses Google Calendar for storage). This gives us a chance to run the algorithm server-side. If you are a fan of programming language other than javascript, or if you would like to use any computing platform, you're open for suggestions :)

ronaldtse commented 7 years ago

As you know I’ve been a big fan of Ruby for the longest time so it’s always Ruby over JavaScript for me :wink:

Bogdan-Kalynovskyi commented 7 years ago

@ronaldtse If we use Firebase for storage than our app becomes serverless again... We could code in Typescript and compute on the client

Haris987 commented 7 years ago

@easy-one I agree on above things related to days identification as integer from January 1st 2017, it makes sense and it is easy to handle it on both sides. Also, time of execution is more logical approach then number of iterations, it is much more transparent for user. With number of iterations it would be hard for user to figure out which number to put in without running algorithm.

Regarding language to use, if it is my choice and it can be any language I would choose c++,it is faster then JS and Ruby for sure. Next choice would be C and then JavaScript :D Never really used Ruby so it would take some time to adapt to its syntax

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 if we choose C++, how do we run it? I can imagine deploying your C++ code to some cloud environment and communicating with it via http... (this is totally my fantasy, I don't know if any easy-to-use solution exists).

Otherwise I suggest using ES6 or TypeScript, and running compiled JavaScript code on client machine. This will run ~2x slower (not counting the fact that the client has slower CPU, it can even be a mobile phone), but we don't need to deploy it anywhere.

PS: I could help with cloud computing, just because I want to have it in my portfolio :)... But I'm worried about http communication part.

PPS: If we use JavaScript, we could easily run it in nodeJs and deploy it on a powerful machine. And the client would not need to download schedules for all users then. I see this as preferred solution now.

@ronaldtse could you please confirm number of people and number of days so that @Haris987 could estimate computation time?

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 ES6 features are mostly supported naively in nodeJs and modern browsers, so I suggest using it. http://incaseofstairs.com/six-speed/

ronaldtse commented 7 years ago

@easy-one I agree that TypeScript or ES6 will work.

Haris987 commented 7 years ago

@easy-one I know it is not common thing to use c++ in web projects, I suggested it mostly because I am most experienced with that and it is faster then js for sure and speed is quite important in our case. One of the options (and more elegant for sure) is definitely exposing it over rest, which can be surprisingly easily done with c++ now using libraries like Pistache or Restbed which was not the case 10 years ago. Another option is exporting c++ function and using it in javascript using ccall/cwrap which I heard that it works fine but never tried it.

JavaScript is totally fine for me too, just do not let me program it in Ruby :)

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 just spent half an hour trying to understand how to deploy C++ code to a cloud and expose it over rest... This is hard for me to understand, so appreciate your help if you are interested. C++ could save you coding time, but deployment seems tricky.

Please note that C++ algorithm would most likely fetch availabilities by its own from firebase https://firebase.google.com/

Haris987 commented 7 years ago

@easy-one What did you used for setting it up? I tried to run Hello World example using restbed deploying it on digital ocean ubuntu instance, and it worked fine: POST http://138.197.7.81:1984/resource

It is definitely harder to deploy it for http then javascript as it it is not so common thing for c++, but it is not so hard. There is also option calling c++ from javascript, that should be much easier

I think there should be some library for c++ with firebase, but if you think it is too complicated, we can use

Haris987 commented 7 years ago

@easy-one JavaScript is really fine for me, no problems, syntax is pretty similar to c++, probably more natural to do it in JS, I won't have problems with it.

I can still help you up setting up server which will server http with c++ :)

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 because C++ and its infrastructure is common to you, everything seems so much easier. But I still feel confused in this playground :)

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 for both languages, I propose the following architecture:

1) the algorithm is run on the server (NodeJs in Javascript case)

2) it's accessible over rest. The api has two endpoints, and two algorithm modes ( maybe this overcomplicates things, probably we will go with one). whatever, here's what I think:

a) POST request, all availabilities are sent in body. This triggers initial schedule creation. The availability and schedule are saved in memory and to Firebase, the schedule also goes to output.

b) POST with user id and his new availability. This triggers schedule recalculation, for this and other users, but probably in different algorithm mode. Changed schedules go to output, availability and schedule are saved to memory and to Firebase.

3) on initial start, availability is got from Firebase, and schedule too, if available. Then they are cached in memory

If we write this in javascript, I can code http and firebase interaction myself. Otherwise I feel like you are the only one who can do it (my knowledge of C++ stack seems to be too low).

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 could you please confirm data format for availability and schedule? I recommend array of day indexes, not ranges. This seems more easy and flexible than ranges.

Example: availability on Jan 01 2017, Jan 02 2017 and Jan 10 2017 will be [0, 1, 9]

Is that ok for you?

Haris987 commented 7 years ago

@easy-one Your suggestions seems totally fine for me, algorithm will be created in javascript, it will make life easier to all of us. One minor thing, maybe to use PUT or PATCH instead of POST for updating schedule, although it is more cosmetic thing then functional :)

Array of day indexes is fine for me, but I would probably rather send list of unavailable days then available, because such list should be much smaller

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 I'm fine with all your suggestions :) @ronaldtse What about days off? Would that be all weekends plus several bank holidays? Or do we need something more complicated?

ronaldtse commented 7 years ago

The structure is fine with me. The current use case specifies days that need scheduling to be only weekdays. I'd say we should specify the "days to schedule" specifically in input.

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 just realized that if we calculate the schedule server-side we no longer have firm restrictions on algorithm working time. We could calculate for long minutes without making the client's computer freeze, and then send notifications through Google Calendar

Haris987 commented 7 years ago

@easy-one I agree, I do not see a use case for setting timeout on user side, except if user needs solution really fast (which is not any use case I think, I doubt that seconds or even minutes are important) I will set some unrealistic timeout internally in algorithm just in case there is a bug and it hangs so it help us to find that bug if it occurs

ronaldtse commented 7 years ago

@Haris987 @easy-one indeed as long as the algorithm doesn't err out, it really shouldn't take that long for a solution 👍

Bogdan-Kalynovskyi commented 7 years ago

@Haris987 since we now have separate schedule for every month, the days could be integers between 0 and 30, not as we planned before.

Are you planning to handle weekends automatically in your algorithm or should the UI send you Saturdays and Sundays ?

ronaldtse commented 7 years ago

@easy-one @Haris987 I think the UI should send the weekends too. In case there will be duty on weekends someday 😉

Haris987 commented 7 years ago

@easy-one @ronaldtse I agree, UI should send it, I think it is much cleaner, user selects working days and you send it to backend as integers [0, 30]

ronaldtse commented 7 years ago

Why don’t we just define a “start” day, and the subsequent duty days after as a list of integers so we are not locked to a month?

Haris987 commented 7 years ago

It is not really important for algorithm whatever is easier to you it will work fine for me too. It is probably better to be prepared on requirement for something different then month so I think it is good idea :)