Traditionally, Mad Devs pays for employees’ lunches. The process starts with food ordering. In the morning a responsible person chooses cafes from Namba Food, opens 2 corporate orders, and asks everyone to choose the food. Then it is necessary to control that everyone ordered food, place the corporate order not later than a given time (otherwise, lunch will come too late) and wait for the operator’s call (to replace dishes that are absent in the cafe — this happens in 95%s of cases). When all the food is delivered, it is necessary to notify everyone one more time.
The process seems very simple but it consumes undeservedly much time of the employees. Therefore, we decided to create a bot. Click here to learn how to Automate the Internship Program
People talk, a creation of bot will take several evenings with beer for a qualified junior developer. However, we are not juniors yet, we are Mad Devs interns and within the scope of routine processes automatization, we got our first real task — to write a bot for ordering food from delivery service app Namba Food.
Before, we have been working on tasks that give us knowledge but do not create any value for the company. In addition, we did not even know how to order food for a small, but very friendly team. At first, we start with the collection of information. The process turned out chaotic and therefore, not very productive. The first prototype of the bot we did blindly.
For the further implementation, we contacted to the True Developer. The position was held by Nakylai, the main backend developer of NambaFood. We discussed the plan of the project, and the puzzle folded. The first revelation happened, and we have got the whole picture of the project. Nakylai created for us endpoints on the opening, closure, view and order statistics, wrote documentation and personally showed how everything works. We proceeded to the realization.
Our team mainly uses two messengers — Telegram и Slack. Therefore, our bot can send messages to both of them. Though it is not a significant achievement, it gives such valuable knowledge as the search of a token in the diversity of API documentation and forces to use different libraries.
We used Python-telegram-bot for the telegram. This is a small library with understandable documentation. For Slack we have written our own functions that definitely took more time, but granted flexibility to the system, that is not provided in standard slack libraries.
CRON is a one more important notion while creating the bot for food ordering. It allows to run functions at the necessary time and not being distracted from work. CRON can invoke your functions outside of the program or can be implemented right into the code. We were working parallel: one intern was writing an external CRON and the other one — small and accurate internal one. By running external CRON you face with the external code and unnecessary complication of the program. Internal CRON may confuse you if you are not sure in your code. Unfortunately, there is no ideal decision. We chose Schedule library as the result.
At this stage, we have the bot that can send specific messages at a specific time: it can ask people to order food or to complete ordering process since the order is closing. It can refer to endpoints: open, close and view the order. Looking at the bot, we understood that it has several functions and correctly performs all of them. Yet, we did not know how to link them into one program that will solve the real problem.
Everything that we wrote earlier is called functional programming. But now the dilemma occurred since we order from two cafes. Should we invoke functions twice? This is not the approach of a programmer. Thanks to the mentor’s advice, we paid attention to the object-oriented programming. One object is created to order food from the 1st cafe, and the other object is created for the 2nd cafe. It sounds very simple, but actually, while we were writing the bot, a lot of new requirements were demanded. Features are changing, everything is broken. Now the fatal issue with token happened!
We decided that it is perfectly fine to use real token right in the code. Fast and convenient. It seems like there are only pluses of using token in the code. It is actually, but only until the moment you have to send a project to the remote repository for the joint development process. So, token got into the repository along with the code. We were laughed and shouted. I cannot say that we have got a serious punishment, but this was the first nervous case during our internship in Mad Devs. The best lesson we learned in this situation is the creation of environment variables.
When we first faced the notion of an environment variable, we identified that it is a dictionary. We created a variable, equated it to the environment variable, but instead of the variable itself, we put its value. There are a key and its value. Is there something wrong?
The wrong thing is the destruction of the essence of environment variables. They are created to hide values, but we displayed them. The right option looks the following way:
- The document with title and value of environment variable that will be activated further should be added to .gitignore and kept by you personally.
- The code keeps only variable titles and the referrals to environment variables. The document is activated by you on your personal computer.
We were done with the project, so it was ready to work. Yet, at this stage, one more technical issue appeared. To run the script we had to put the project into docker container and put it on the server. No sooner said is done.
When you work with scripts without the databases and other joy of backend, everything is simple and carefree. We created requirements documented that is connected to docker and allows it to download all necessary things. What is more, we specify the base image and commend docker to rerun automatically if it falls down.
The first time of launch! Everything was checked for a lot of times and the results were successful. The bot is opening the order… But one cafe appeared from nowhere, not from our list! This happened due to the differences between cafe indexes at the staging and at production. The mistake helped us to understand the importance of data rechecks for a “real” server.
The next day is Saturday. It is a day when we usually have a rest and do not go to the office, the bot should relax as well. However, he opened an order as if he was a very diligent worker. What is worse is that cafes on the list were the same as the day before while two cafes should be opened from the list randomly. We concluded two things from the situation. The first thing we should do is to write the script for time updates in the docker. The second one is that random choice is not always random. Therefore, it is better to use “for” cycle and to clearly set a sequence of cafes.
Here is our one more mistake. Since we order different bread from different cafes (flat cakes or boorsoks), we decided not to place “if” clauses into the code and write the information about bread into the comments for operators. The comments were similar to this:“If the order is from “Diyar” cafe, then order 2 kilos of boorsoks, if the order is from “Taste of the East”, then order 5 flat cakes, etc. We describe all 12 cafe optionsin comments… As a result, we got very angry NambaFood operators and blow-up from mentors. This experience let us learn a new lesson:
It is necessary to care about the end users of the product more than about the accuracy of the code. Users in no case should suffer from your unwillingness to write bad code and your inability to avoid it.
A long time passed before we could run the bot. Now, it fully works and orders food for everyone in the office. Unfortunately, the bot can not entirely replace people in the food order.Can not do this yet, but will definitely do so in the future.
Now we have a plenty of feedback from users and plans for the improvement:
- Check of the status of the order and automatic delivery information;
- Entrust the choice of cafe to the staff through voting;
- Automatic order of bread;
- Automatic replacement of the dish if there is not ordered the dish in the cafe.
- And some more wishes like “…considering the current weather, weekday and moon phase determine the employee’s mood and order him food according to it without the participation of the employee himself…” (I hope that it will be implemented by our future interns =))
- You should learn to use environmental variables from the very beginning, otherwise — FAIL!
- You must check time inside the docker-container.
- Random choice between very few options often gives out a similar or identical set and therefore seems not working.
- Data on the “real” production server may and likely will differ from the data on the test server.
- Code may not be accurate, but it has to work as expected. If you doubt, it is better not to release.
- In the production environment, you can run only well-tested features. All the routine performance checks have to be conducted in the test environment, without disturbing future users.
- It is better to collect all the feedback for the product in one document instead of listening to the users (otherwise, it is easy to forget something).
The main conclusion:
The product that we create, has to solve the problem. We write code to improve the life, solve real problems instead of creating new ones.
Read here how to test your bot without using real slack servers.