We, the
elephant math camp , have long been holding summer and winter schools for students in grades 8-11. The main activity at the school is working on a major task, a project. This can be anything from modeling a complex physical system to a program for breaking ciphers or writing a toy for Android. Most of the projects at school are somehow related to programming, but rarely programming is an end in itself of a project. Schoolchildren who have not yet had time to become experienced programmers, and even in the conditions of an eternal shortage of time, they write the code “Schaub worked.” So we know firsthand what a bad code is and every year we meet new, sometimes even surprising, ways to make the code unreadable - and every year we decide what to do with this problem.
For example, last year we have been carrying out code-review tasks for the introductory task. True, our code-review is voluntary: we point out the students' mistakes, but do not force them to rewrite the code (less effectively, but more humanely). This idea seems to us successful, although it takes a lot of time from the reviewers.
Another idea was to use git, "so that everyone could see the crap." Then, towards the end of the project, it would be possible to revise where everything started and where it turned out, to be terrified and to do differently. However, this idea did not pass the test of time. In our experience, schoolchildren are difficult to teach using the version control system, and even regularly. They do not understand why hard currency is needed, and therefore they are bored. In addition, to take a couple of hours just to master git is insane waste for a project of one week in length. And not for the version control system originally thought.
')
We really liked the solution we used this winter, so we consider it necessary to share our method. We called it
"Mad Tea Party .
"So, the task: to teach schoolchildren to write clear and neat code. At the same time it is necessary to make this process fascinating ...
To learn how to write good code, we usually look at examples of good code and bad code. Pupils usually look only at their own code. The course is designed to change this practice: participants look at the good code and the bad code and write the code themselves. Usually, children play the role of being criticized, while on a special course they had the opportunity to look at someone else’s code, criticize it themselves and try to improve it. How?
We took one task, the conditions of which can vary greatly (we had Konveyev's game “Life”) and divided it into several small stages. The splitting is done so that at the end of each iteration a ready working program is obtained. The stages themselves are rather small, so that in one lesson (1.5 hours long) they can be completed, sometimes even 1.5 iterations can fit in 1.5 hours.
Future iterations to participants are not known in advance, so where it was easy to “put straws” on the current iteration to do the next iteration is also unknown to them.
At the beginning, students are given the task of the first stage. After it was completed by all participants, it was time to "change". Participants exchanged decisions and received tasks of the second stage. Now they had to figure out the code of others and modify it so that it solved the problem of the second stage. At the same time, it was allowed to refactor the code and correct other people's errors, but it was completely forbidden to rewrite the code. After the second stage, the schoolchildren again exchanged solutions and again continued to write the code, and again on a new basis for them. Communication between the participants of the special course is limited, so it was possible to find out “what a horror is written here”, only by reading the code. Between iterations, recurring style errors were recommended, which were recommended to be corrected.
There were five schoolchildren on our special course and, accordingly, five projects. Three students worked on each file at different points in time. When after a few iterations, their own code once reached them, it was already very different from what they originally wrote. The foreign code with which they worked at the previous iteration turned out to be more “theirs” for them than their own code, which came to them after passing through all the other participants.
It is also important that schoolchildren exchange the code not in a circle, otherwise at each iteration the participant will receive a code from the hands of the same person.
But let's get the details, so interesting. As I have already said, the global task was to write Konveyevsky game “Life”, but this task was unknown in advance. The tasks of the stages were as follows:
- We write the one-dimensional game "Life" (aka elementary cellular automaton ), the playing field 200 cells in size. A cell survives or is born if it has exactly one neighbor. For the extreme points of the "neighbor" abroad is always "dead." Initially, we fill the field with living cells so that the numbers of living cells make a geometric progression with a factor of 2. Each turn occurs by pressing the Enter key.
- We allow the user to enter the field size and the coefficient of geometric progression. Add the ability to enter the command “W” to do not one, but 10 steps at once.
- We give the user the opportunity to specify the initial configuration of the field: the user enters a number, his binary representation specifies which cells are alive (bit 1) and which are dead (bit 0). It is also necessary to make a check that the initially specified configuration fits in the specified field size. Add the command "R", which restarts the program.
- We change the rules of survival: a cell with one neighbor now survives, and it originates from nothing if there is a neighbor to the left. We supplement the “W” option so that you can enter the number of steps that the field has to do.
- The rules of life are now set from 0 to 255: for each of the eight initial configurations (a central cell with two adjacent ones, each in one of two positions), one bit is set: what should be the cell in the next step.
By the way, this modification of "Life" can be guessed.Excerpt from the school newspaper:
"Mad tea drinking" predicts the fate of the one-dimensional game "Life": we introduce age as a rule - we look at the development of cells. Such highly plausible results were obtained: at the age of 16 and beyond, everything is hopelessly bad, and everyone constantly goes into the sunset; at 23, finally comes stability; sometimes you can still live, if to be together. The editorial staff - an expert on the game "Life" adds that at 25 this fortune-telling predicts reproduction, which is typical. Universal knowledge, as we remember from the lecture , will come to 110 .
- Add save and load fields and rules.
- We transfer the game to the two-dimensional world. Now the rules are set in the standard way: the number of neighbors to survive and the number of neighbors to come to life; field status is set line by line.
All students in our school wrote in Python, but the programming skills of the participants were quite different. The format of the task is such that the difference in the level of people in a group is not a minus, but a significant plus. Using one common programming language is convenient, but not necessary. It is possible that the use of several languages will make the course even more fascinating, because in real life, sometimes you have to read and edit code in an unfamiliar language.
We did not force schoolchildren to use a version control system, but for convenience we brought the materials into one
repository . Quite fascinating reading for those who are interested in learning programming.
For
all normal people who don’t want to poke around in someone else’s code, I’ll give my own observations and analysis of errors: both schoolchildren’s mistakes and our own ones.
The exchange of code between the participants extremely successfully smoothed the quality of the code base. Even if the program began with a multitude of single-letter variables and the absence of modularity, then after a couple of iterations, someone would certainly give the variables good names, structure the file, simplify the code. And spoiling someone else's (relatively) good code - you still have to try it; easier to fit into someone else's style. In addition, students pick up from each other (or from the teacher?) Favorite patterns. Sometimes good.
However, contrary to our expectations, over time the code became more and more dissimilar. Once decisions were made, they continued to live and develop, although they fell into the hands of people who did it differently. However, in fairness, it was not always. It was hard for some participants to come to terms with the fact that someone solved the problem differently, and they sat down to rewrite normal working pieces of code in their own way ... And they did not always do it better. And the names of the variables were as changeable as their contents. Apparently, it is worthwhile to introduce some formal restrictions on the scale of changes.
According to the author of the course, the “Mad Tea Party” is best influenced by middle school students, and least of all by the weakest and strongest schoolchild. The weakest always get a very decent code by his standards, and the strongest doesn’t have anyone to match. It is possible to improve this situation if the teacher of the course himself participates in writing the code, as additional two participants. The first such participant will write the refactor and change the code as if he would write it himself, and the second will make an artificially bad code worse than the weakest participant.
I must say, some of our schoolchildren are good at writing in OOP-style. And so it is rather remarkable that they did not use it even where OOP suggests itself. It seems that for them objects are not an obvious choice when it comes to simplifying the code. It is not enough to learn how to write your classes, you need to train in which cases the use of classes will improve the program. In future incarnations of the course it is worth considering.
As I mentioned, the names of variables and functions cause wars of edits. This, I think, is connected not only with taste preferences, but also with the fact that many of the names were very unsuccessful, and the good names were successfully fixed. All my experience in teaching programming says that beginners (even fully adult beginners) are not able to name variables meaningfully, since they cannot describe what this variable holds.
One of the reasons for this misunderstanding is the idea of a variable as some kind of “box” in which you can put a value, read a value and change a value. The name “variable” itself suggests that they are created so that the value changes in them, and it is not so easy to clearly describe the meaning of an object that stores different contents at different times. Sometimes it's just impossible. Reuse of the same variable is probably useful in high-performance applications in low-level languages (and only if the compiler does not do well with optimization), but in the modern world this is not the most meaningful use of the language features. Usually these are some kind of innocuous small conversions: they added a couple of characters to the string, rounded the number, converted the string into a number. For example, two fictitious cells at the edges were added to the field and recorded in the same variable. And now not to say what lies in the variable: a number or its string representation? field or extended field? This seems like a trifle, but the quality of the code is one of them. And such trifles can spoil a lot of blood when refactoring.
I am not an ardent apologist for functional programming languages, but the concept of immutable variables can be very useful for creating habits of good code style.
Another reason is that many simply lazy to concentrate and formulate the meaning of the variable. Often the name reflects not the content of the variable, but its form. For example, at the third stage, it became possible to set the initial configuration of the field with a decimal number, which, when converted to binary form, would give a configuration. In 4 programs of 5, this variable was called `number` or` decimalNumber`, and not `initialFieldPosition` or` aliveCellsEncoded` at all. Then these names changed several times to please the tastes of this or that programmer, but they never acquired a complete and logical name. Unlike many other variables, which, having acquired their true name, stopped these throwings. Or here is `count_symb`, what is it? In fact, the length of the field - and all because the field is represented by a string, so the number of characters represents the length of the string.
The third reason is not knowing the language. It is difficult to formulate your thought in a language you do not know. One of the outputs that some people use is to output along with the task a glossary of terms on the subject of the task.
The names of the functions occur similar wars edits. Some of the reasons are similar, but there are specific ones. The fact is that the new code is usually written where it is easier to add it, and not where it is more logical. If you need to add a function argument or a return parameter (remember, we write in python?), It is added without a twinge of conscience. In a successful case, the function name changes accordingly, but not always. After some time, the meaning of the actions performed by the function has a very conventional relation to its name. What to do with this problem is not yet clear. One option is to prohibit schoolchildren from changing the type of value returned by the function and to make a clear division into functions that produce actions and return results. However, it is naive to believe that such a ban will work.
Despite all the shortcomings, the course helped schoolchildren learn to write almost sane code, and also allowed them to experience all the pain experienced by the teachers reading their programs. ;)
The course “Mad Tea Party” was designed and conducted by
Pavel Smirnov . I just asked the author, read the resulting source codes of the programs and wrote down my observations.
PS The course does not teach how to write a product that is carefully thought out a few steps ahead, but how to work with someone else's code, how to gradually improve it and not allow the program to turn into something terrible.