Created: May 14, 2018

Food Ordering Bot and First Test for the Intern in Mad Devs

Asadov Ahmed.

Asadov Ahmed

ex Software Engineer

Software Development
Food Ordering Bot and First Test for the Intern in Mad Devs

Introduction

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 no 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% 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.

Intern's test

People talk, creating a 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 the delivery service app Namba Food.

Before, we had been working on tasks that gave us knowledge but did 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 started with the collection of information. The process turned out chaotic and therefore not very productive. The prototype of the bot we did blindly.

For further implementation, we contacted 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 got the whole picture of the project. Nakylai created endpoints for us for opening, closing, viewing, 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 valuable knowledge as the search for a token in the diversity of API documentation and forces us to use different libraries.

We used Python-telegram-bot for 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 one more important notion when creating the bot for food ordering. It allows you to run functions at the necessary time and not be distracted from work. CRON can invoke your functions outside of the program or can be implemented right into the code. We were working in parallel: one intern was writing an external CRON and the other one — a small and accurate internal one. By running an external CRON, you face external code and unnecessary complications in the program. An internal CRON may confuse you if you are not sure of your code. Unfortunately, there is no ideal decision. We chose the Schedule library as the result.

At this stage, we have a bot that can send specific messages at a specific time: it can ask people to order food or to complete the 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 ordered 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 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 the token happened!

We decided that it is perfectly fine to use a real token right in the code. Fast and convenient. It seems like there are only pluses of using a 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, the token got into the repository along with the code. We were laughed at and shouted at. I cannot say that we 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 is 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:

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 a Docker container and put it on the server. No sooner said than done.

When you work with scripts without the databases and other joys of the backend, everything is simple and carefree. We created requirements documented that are connected to Docker and allow it to download all necessary things. What is more, we specify the base image and commend docker to rerun automatically if it fails.

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 were a very diligent worker. What is worse is that the 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 Docker. The second one is that random choice is not always random. Therefore, it is better to use a "for" cycle and to clearly set a sequence of cafes.

Here is 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 the 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 described all 12 cafe options in comments… As a result, we got very angry Namba Food operators and a blow-up from mentors. This experience taught us 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 food ordering. Can not do this yet, but will definitely do so in the future.

Now we have plenty of feedback from users and plans for improvement:

Lessons learned

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.