Does The Programmer Have a Chance To Avoid Simple Mistakes?
27 May 2020
I have seen once such a meme: “If debugging serves to remove errors from the code, programming certainly involves inserting bugs into the code.” There is some truth in it. Modern IT systems implement a lot of very complex processes, it is very easy to make a mistake. The programmer creates a tool that can be used in different cases. Testers and then end users will apply this tool in a way that the author hadn’t even imagined before. Combining this with ordinary human error during software development creates a mix that sooner or later will always “explode”.
So how should a programmer work so that the effects of his work are not negatively assessed after just a few clicks? Does the programmer have a chance to avoid simple mistakes? I have been creating a business application for companies and institutions for over 15 years. Over the years, I have developed a pattern that allows me to discover many simple errors at an early stage. This is a set of simple tests that significantly increases the quality of the produced software. Applied together with automatic tests (from unit to integration) they give a chance to eliminate many mistakes.
Most consumer applications can be generalized according to the following scheme:
No matter if we create a module of invoices, complaints, orders, reports, users, we can more or less always find the above pattern.
I wrote the functionality, what’s next?
The first problem that appears during simple tests performed by the programmer is the approach to the pattern of permissions. The programmer will perform the test using the role with the highest permission. In this way, I want to check if all components are working properly. It is a mistake to stop at such testing. Majority of future users will operate on the minimum permission required. It is worth enriching the basic check of the new functionality with the lowest possible permission to perform a given operation. Such a test allows to:
- verify if the system of user rights and roles works properly,
- check if items available only to the administrator will be properly hidden or deactivated,
- verify whether the lack of administrative data is an obstacle to the application’s operation,
- check if, for example, the record passes successfully for a user with the rights different than the administrator’s rights.
A perceptive reader will probably immediately think about the roles of users who can do more than the lowest role, but are not administrators. Should the programmer check all possible cases? Yes, because he or she should verify if the settings work for other roles or claims. No, because he or she does not have to log into the system thoroughly for every possible type of user verifying the operation. What about the other cases? Cold calculation of the code and delegation the functionality to a tester allow to eliminate most errors in this area.
The ability to create new and to edit existing elements is the basic functionality of each module. By performing the following simple tests many different cases of application can be verified. When testing a user form (or dedicated API) for creating or editing, it is worth following the path below:
- Minimal filling — only required fields — allows to check whether such a set of data is really enough?
- Maximum filling — allows you to check if all data are saved?
- Boundary conditions for fields — allows to check if validation works as expected.
- Positive test — allows you to check if the system works for correct data?
- Negative test — allows you to check if the system stops working for incorrect data and correctly informs the user about it?
- Save — allows you to check if the change will actually be saved in a database?
- Update — allows to check if the object will be modified?
- Delete — allows you to check if the object can be deleted?
- Navigation — allows you to check if the transitions are working properly, in the case of the form, you can check it for in and out?
It should be a good practice to verify such operations as: saving, modifying or deleting directly on the database. When verifying the record, it is worth verifying that the data is being written to the appropriate columns and whether they are read and displayed correctly. This is to eliminate mistakes in the style of saving the net amount in the place for the gross amount and vice versa.
In the above method it is not possible to check all test cases, but it is possible to check if all the applied mechanisms work. At the testing stage, we should receive the answer whether these mechanisms are working properly.
Another very common element to check is the list of elements, the table. Very often it will be a view from which you go to the edit form. Here you can again talk about a simple list of tests that allow for an initial assessment of the programmer’s work effect:
- Fetching data — we check if the data is in each column?
- Filtering / Searching — we check if the search engine returns filtered data?
- Pagination — we check if the paging mechanism works, and, whether filtering also works on subsequent pages?
- Transitions — we check if you can go to details etc.?
- Going to editing — allows you to check whether the user will be redirected to the correct record according to his authorization level?
At this stage, it is also worth checking if there is a mistake regarding the assignment of data to the appropriate columns in the appropriate format — here it is very easy to make a mistake.
The Report, The printout
All types of printouts, reports, statements are very difficult to test and verify. It is necessary to prepare a set of test data and maintain it at a level adequate to the current state of application development. This will keep the data source in a state that allows you to verify, for example, invoice printout or a sales report over a given period. How to construct such a set of test data:
- Minimal — an object containing only the minimum data necessary for its recording.
- Maximum — an object containing all possible data.
- Most common — an object that contains a set of the most common data if it can be defined.
- In a different language version — at least one object in a different language version if the system provides such a possibility.
Because work on e.g. the invoice module can be significantly extended in time, it is also worth updating the status of your own test data set with subsequent system updates. Contrary to appearances, this allows you to significantly save time by being constantly ready for testing.
After preparing the script or package updating the database and running it on the development machine, I strongly recommend that you should do this test also on the test machine. Configuration or server versions may differ between the development environment and the server. Verification of changes is a must.
Debug — Release
We are happy to use conditional compilation. It allows, for example, to write code that will perform the required task step by step — just in time for the needs of the debugger. This carries the risk of not adapting the code changes to the Release version. Therefore, checking tests should be done in Release mode. Surprisingly, you can do such tests on the programmer’s computer.
Modern systems are very complex and carry out very complex tasks. However, they can be systematized into fragments that can be described as successive CRUD elements. By using the presented set of simple tests you can eliminate many errors. In addition, by testing at a low level of permissions in a production-close environment, you can avoid many unpleasant surprises. I encourage you to create your own list of steps to verify the new code.