To work in a project without mistakes is the dream of any IT person. Is this achievable in reality? This question is both simple and complex, because, in order to avoid mistakes, it is necessary on the one hand to have a strictly verified chain, ranging from the formation of general requirements to detailed implementation. On the other hand, a stream of specialists is pouring into the IT sphere who have little idea how to prove the absence of errors in a program or build a structure that reduces the possibilities of errors, above all logical ones, which are of a fundamental nature.
Initially, programming has grown out of mathematics, but over time has lost the rigor familiar to mathematics. Nevertheless, the connection with mathematics continues to exist. To solve some of the problems come to the aid sections of discrete mathematics and logic, which bring clarity and uniqueness. Discrete mathematics is well suited to formalize business automation systems, since most business processes have discrete characteristics. For example, the number of types of contracts is calculated in units, tens, rarely hundreds. Dates also have a discrete nature, their number is proportional to the number of days in a year. Cash transactions, which seem to be described by floating-point numbers, are in fact in most cases accurately described by an integer number of kopecks or cents. Therefore, the number of cents or cents that has passed through the organization over the entire period of its existence is described by a very specific natural number. And by the standards of modern mathematics, all these numbers are very small.
For math, the question is clear. There is a countable limited number of objects, a countable limited number of degrees of freedom, the states of objects, etc., etc. All specifications are amenable to simple counting. Estimates and calculations for countable finite sets are not difficult. A person who has completed a course of combinatorics or discrete mathematics will be able to outline a plan how to formalize all possible states of the system and how to isolate correct and incorrect states. This is what mathematics can do:
- counting the number of possible options for the state of the object;
- proof of completeness, whether all options are considered or there are unaccounted for;
- proof of the presence or absence of incorrect states;
- search for examples that lead to incorrect or correct states;
- evidence of equivalence of certain actions;
- and much more.
Now we will try to deal with the insidious enemy, which complicates this process. For example, the author of a TK transmits a certain list of types of contracts for which some action will be performed. Sometimes the phrase “all types of contracts” or “all other types of contracts, except ...” may appear in the ToR. The programmer seeks to perform the TOR correctly with a lack of time and pressure from the business. It is often not necessary to think about how much the program is ready for new changes - just to pass the tests, correct the comments, hand over, report, go on.
')
Suppose a programmer does a procedure that inserts an account number in an accounting entry. Seeing the list of all types of contracts that are present in the system or seeing the phrase “all types of contracts”, the programmer makes the first mistake - he summarizes what may even be pleasant for the brain, because you can express the idea briefly. As a result, his procedure that submits an invoice does not analyze the type of contract. At first glance, there is no crime.
That's the catch - you see, the concept of “all types of contracts” at the time of writing the TOR included 10 types. Then this concept is changed, and in half a year a couple more types are added. And whether they will fit into the old logic is incomprehensible.
In large projects, there are many more places where a new handler can be inserted. The first programmer has long switched to other tasks and forgot where and how the bill is substituted depending on the type. The task of processing a new type of contract can be assigned to another programmer who, having studied the system, has found a new place where a handler can be added. For example, the second will finish processing in another place: on the client, in the procedure on the server, or in the trigger or somewhere else. Because of such wanderings, logic over time becomes little understood. Processing the rules and exceptions to the rules in the most unexpected places, and the code gets confused.
If you're lucky, the new type of contract will have little difference from the previous ones. And most likely, handlers who allowed generalizations and did not analyze the entry of an unfamiliar element will work correctly. But every experienced programmer, met with a situation where the customer brought new and new requirements, breaking the carefully constructed schemes. It is difficult to predict how the program will behave after the addition of a new type of contract, which has been developing for several years by a team of tens or hundreds of employees, who now and then allowed partial or complete generalizations or discrepancies. The old universal procedures and functions begin to gradually work under more and more new types of contracts, and more and more data depends on their work. Over time, it becomes more and more risky to get into these procedures and functions, since any correction can damage the system, and it takes a long time to correct the curved data, restore from backup copies, analyze the history of changes. Due to discrepancies, there are backlashes, where they should not be and rigid structures where they are out of place. The project becomes like a car that has a gearbox jammed and the steering wheel dangles back and forth.
The way out of this situation suggests itself - it is necessary to fix the lists of contract types at the stage of technical assignment or subsequent technical design, and in case the program encounters an unfamiliar type, then give an error. So the generalizations that are harmful for formalization are removed, and the program will automatically signal from all places, if it suddenly encounters a new unrecorded type. Developers will know where to take into account new elements, and not to use a new version of wedging into the old code each time.
How much benefit from this judge for yourself.
- Disagreements between the originator of the TOR and the developer are reduced. Common words are supported by specifics.
- The likelihood that the debugged algorithm will get the parameters on which it was not tested decreases.
- There are visible places in the code where you need to add processing of new types.
- Increases the level of discipline in the code. The probability increases that the logic will be concentrated in the same place, and will not be scattered.
- Facilitates formalization and automatic code analysis.
I do not offer hardcode lists when they can be maintained in the database. Just cite the simplest examples to illustrate the principles on pseudocode, similar to pl / sql.
I plan to write a sequel to the following topics:
- how to handle type / sub-type condition bundles
- how to automatically detect conflicting requirements in TK
- how to automate the creation of lists and allow the analyst to manage them
- how to use math to analyze a system
- project development through meta systems
D.A.Rybakov, 2016
Ph.D.