Programming to the masses

Understanding even the basics of programming can simplify human activities. In addition to the obvious things, such as the development of abstract thinking or the ability to divide the task into smaller parts, I propose to go even further and use the basic approaches to development. Using the example of creating a classic logic game, drawing an analogy between visual and traditional programming, I want to show how development skills can help in solving an applied problem. Those wishing to debate on the topic or play "Bulls and Cows" and win a prize - a call to cat.



My name is Zhenya and I am a backend developer at ManyChat. Some time ago, the HR team approached me with a request to implement the game “Bulls and Cows”, familiar to many from childhood, on the basis of our product. Let me add a little context. ManyChat is a tool for automating the interaction between businesses and their customers, allowing you to answer common questions via Facebook, and more recently SMS and Email. “Bulls and Cows” is a logical game, during which, for several attempts, it is necessary to guess the guessed number. Many can know it from the game Fallout, where you need to hack a computer terminal. More details about the rules can be found at the end of the article.

Visualization


What do we do before writing code for a complex task? We go to the blackboard with a marker or pick up a pencil and paper and draw a block diagram or UML diagram, because visualization is the most natural way for people to present and perceive information. Flow Builder is the heart of our system, based on various objects, graphic elements and the rules by which they interact with each other. I would say that this is a logical continuation of object-oriented programming. So I discarded the usual tools and immediately proceeded to designing the logic of communication between the bot and the player.

Flow of the Bulls and Cows game

This is very convenient, since the UML diagram and Flow Builder are almost identical. At this step, design and programming are already combined. For several iterations, I threw flow and designated the places of interaction with the user and with the API. The result obtained was somewhat different from the original representation in my head - visualization provided an opportunity to look at the task from a different perspective. This is good, since changes to the diagram are easier and cheaper than to code. It seems to me that the meaning of this approach is rooted in the proverb “measure seven times, cut one”. Engineers should be especially familiar and understandable.

Division of responsibility


What should be implemented on the side of ManyChat, and what on the side of code? The answer to this question at first did not seem obvious to me. There are two tools for interaction on our platform: Dynamic Block and External Request. They are almost identical except that the first one executes the request to the remote server and moves on to the next instruction, and the second one allows you to first compare the response data with the bot variables. In one of the first versions, I used the Dynamic block and implemented sending the standings from the API method directly to Facebook. It would seem that there is nothing wrong with this approach. But if you look a little further and assume that the player wants to play using SMS, the code will have to find out about the communication channel of a specific player. It does not seem necessary. In the next version, I switched flow to work with External Request,added a response record to user variables and removed any mention of the channel from the code. Now the game code can be used in another application and implement any desired interaction interface: from the console to the mobile application. Whether it was separating the view from the control logic according to the MVC pattern or highlighting the limited contexts according to the DDD approach - decide for yourself. The main thing here is that despite the lack of requirements, on a subconscious level, I identified a potentially bottleneck in the system that could create problems in the future.Whether it was separating the view from the control logic according to the MVC pattern or highlighting the limited contexts according to the DDD approach - decide for yourself. The main thing here is that despite the lack of requirements, on a subconscious level, I identified a potentially bottleneck in the system that could create problems in the future.Whether it was separating the view from the control logic according to the MVC pattern or highlighting the limited contexts according to the DDD approach - decide for yourself. The main thing here is that despite the lack of requirements, on a subconscious level, I identified a potentially bottleneck in the system that could create problems in the future.

Variable naming


Variable naming is one of two major programming problems. In addition to variables, block naming is equally important. Many users do not attach importance to this, do not have time to look around as flow turns into a set of Copy 1, Copy 2, and so on. This greatly complicates the understanding. Everything is like with a bad class - it is impossible to figure out what he is doing without going inside. In more detail this thought was revealed by my colleague. If you are interested, I suggest that you read his post .

Steve McConnell in his book "Perfect Code" wrote that the name should fully and accurately describe the represented entity. I think it's hard to argue with that. For example, for boolean variables, I prefer to use the is prefix. In this case, the reader can already understand what he is dealing with by the first two letters. As for the length, it is desirable that it does not exceed 20 characters (Gorla, Benander, and Benander, 1990). The smaller the scope of a variable, the shorter its name can be. But since all the variables in ManyChat have a global scope, it is worth using the namespace. For Bulls and Cows, I used the starting segment in the form of two BC capital letters derived from Bulls and Cows. Given the above, I got the variable name BC Is Victory - quite unique and comprehensive, in my opinion.

DRY, KISS


The game works and, it would seem, you can exhale with a sense of accomplishment. But we know that the next step is self-review and refactoring. With a more detailed analysis, you can see how stop word processing and victory lead to similar blocks - player calls for some actions. At the same time, the loss, for some unknown reason, lives its own life. Combining these places into one seems to be a logical step to avoid duplication, which in turn leads to increased consistency of behavior and ease of maintenance. Now, if changes are necessary, you need to make them in the only unit of the system without changes in others, which indicates that the principle Don’t repeat yourself is applied successfully.


Flow with DRY

However, do not stop there. Complex solutions are difficult to maintain. When an error occurs, it will not be easy to localize it, especially after a time when you fall out of context. A new person will take a lot of energy to figure out what's what. And you will have to familiarize yourself with each node, so as not to miss anything important. Therefore, it is worth using the principle of Keep it simple, stupid and spread all the possible actions into separate places. After decomposition, I got 5 fairly easy to understand flow. As a pleasant bonus, this refactoring satisfied Single responsibilityprinciple. Each flow has one responsibility and this responsibility is completely encapsulated in it. The appeal is a la Black box, and by the nature of the problem it can be localized faster.


KISS-compliant Flow

YAGNI


In one of the first versions of automation, there were achievements in sending reminders of an abandoned game and instructions for receiving gifts by the winners. The implementation of the first idea was complicated by restrictions on the part of Facebook - recently the conditions for sending messages outside the window at 24 hours have become tougher. The second turned out to be insufficiently trivial for implementation by the code. Both issues are resolved, but the amount of effort needed was not justified by the needs of a one-time campaign. In addition, sprint tasks stepped on the heels, so it was decided not to implement this functionality. And here came to the rescue You aren't gonna need ita principle whose purpose is to abstain from excessive functionality. This is a normal situation when conditions change and dead, more unnecessary parts appear in the product. Removing the corresponding blocks facilitated an understanding of the purpose of flow and once again reminded the importance of timely refusal to add new functionality, which is not directly needed.

Experienced developers know that any feature needs constant support, from code refactoring to updating documentation and working with user feedback. Therefore, the addition of new functionality should always be regarded with suspicion, asking the question, is it really necessary? Ultimately, at this stage, you can save a lot of resources.

let's play


The stages of self-review and refactoring are passed, there is no unnecessary functionality, and the meaning of all flow is transparent for understanding. This means that the game is ready and it is time to compete for prizes. According to the terms of the competition, the top 10 players who score the most points before May 22, 2020 will receive prizes from the ManyChat team.

A bit about the rules. In our implementation, the game is designed for one person. The bot makes a 4-digit sequence with non-repeating numbers. The player makes an attempt to guess the number. The bot reports in response to how many numbers were guessed without coincidence with their positions, that is, the number of cows, and how many were guessed right up to the position, that is, the number of bulls. As a result, the game scenario may look something like this:

The number 1234 is guessed. The
participant makes the first assumption: 4321
Gets the answer: 0 bulls and 4 cows. The
participant makes the second assumption: 1678
And receives the answer: 1 bull and 0 cows.

To try, follow the link and follow the prompts. Let me remind you that the game goes through Facebook Messenger. We offer 2 difficulty levels: a game for a limited and unlimited number of moves. Victory in a difficult one will bring you 3 points, in a simple one - 2. Losing, regardless of level, will take 1 point.

The game was implemented on a standard technology stack: Nginx 1.17, PHP 7.4, PostgreSQL 12.1. If you wish, you can clone the repository to your server, install the template on your ManyChat page and arrange your own tournament.

findings


“Everyone in this country needs to learn how to program on a computer because it teaches you to think.” I think that the relevance of this statement has long gone beyond the borders of only one country. Programming is not secret characters in the terminal, difficult for an uninitiated person to perceive, and a programmer is not an elected one. First of all, it is a way of thinking and a set of skills for solving problems.

Turning to the title of the article and the original slogan, I want to rephrase it: “Programming belongs to the people. It must have its deepest roots in the very depths of the broad working masses. It must be understood by these masses and loved by them. ”

I would never have thought that in one article I would quote Steve Jobs and Lenin.

I am sure that the thoughts presented here came to my mind not only to me. Some will even consider them captains. But I know for myself that sometimes you need to hear the same information several times in order to start using it. The banal principle is to simplify things as simple as they seem. Every programmer knows that the project code quickly and easily gets out of hand if not given due attention. But sometimes you have to remind yourself of this again.

Something was not lit at all. For example, extreme programming techniques such as pair programming, frequent small releases, and the game of scheduling were not addressed in this article. Although flexible methodologies have common roots with systems for organizing offline, physical production, they are still often used for software development. Although their potential is not limited to the industry.

There is probably something that I never thought about. Each of us has his own experience and vision. Therefore, I urge you to share your thoughts on this subject in the comments.

All Articles