📜 ⬆️ ⬇️

An example of writing functional requirements for an Enterprise system

Recently, a friend of mine, a programmer, said that he does not read the requirements, but instead invites the analyst for a cup of tea, they sit down together, and the analyst tells what needs to be implemented. My friend is a smart person and a good programmer, and the reason why he gets knowledge about the requirements is that way, not that he is too lazy to read the documentation, but that, even after reading it, he will not fully understand what to do. In this article I want to tell how you can write requirements for a software product so that programmers do not just use the requirements, but also participate in writing them; based on my own experience, I want to show how to describe the requirements for these descriptions to be sufficient for the implementation of the system.

The goal of our development was to create a zero-level accounting system for one of the large Russian companies. The system was designed to replace the current, written in the late 90s. As a result, the platform and one of the business modules were implemented. In the realized part there were about 120 objects, 180 tables, about 30 printed forms.

I want to make a reservation that the approach described below is not universal for writing any software. It is suitable for enterprise-level systems that are built on the basis of an object-oriented approach: accounting, CRM, ERP systems, workflow systems, etc.
')
All documentation for our software product consisted of the following sections:

The general part consisted of only two sections: a list of terms and their definitions and a description of the business roles of users. Any system documentation, including, for example, test scripts, was based on the definitions given here.

Business requirements described what business users need. For example, they do not need the User object at all, but they need to be able to change the value of the goods on the invoice and print it. Business requirements consisted of common scenarios, use cases (use cases) and descriptions of data processing algorithms. Details on the development of such requirements can be found in the book by Karl I. Wigers and Joey Beatty Developing Software Requirements .

System requirements described the properties and methods of all objects in the system.

Non-functional requirements in this article we will not touch. I can only refer you to the excellent book Architecting Enterprise Solutions by Paul Dyson, Andrew Longshaw.

Integration requirements described a low-level interface for interfacing a new system with several other company systems. Here we will not consider them.

User interface requirements are a separate large topic, perhaps for another article.

Also here I will not touch on other sections of the documentation that relate to implementation, testing, guidance and management.

Let's take a closer look at what the list of terms is and why it is needed.

List of terms and definitions


Very often when discussing the functionality of the system, the conversation comes to a standstill. Even worse, if the parties disagree, thinking that they have agreed on everything, but as a result they have a different understanding of what needs to be done. This happens not in the last degree due to the fact that initially the project participants could not agree on what the terms mean. It happens that even the simplest words cause problems: what is a user, how does a group differ from a role, who is a client. Therefore, unlike the description of business roles for terms, it is necessary to give as precise definitions as possible.

Let me explain this by the example of the term User . Wikipedia gives the following definition:

User - a person or organization that uses the current system to perform a specific function.

But it did not suit us for several reasons. First, only a person can enter the system, but not an organization. Secondly, for our system, the present verb incorrectly “uses” - the system stores data about inactive or remote users, i.e. about those who used the system earlier, but can not currently. Finally, we have data on potential users. For example, we register an employee of a client company who may later receive (or may not get) access to the system. Our definition:

User - a person who has, had, or may have access to the system for performing transactions.
Now the programmer, having read the definition, will immediately understand why the Login property in the User object is not mandatory.

Terms are related to each other. The term User uses “operation”, therefore I will give its definition:

Operation - a set of actions that make up the content of a single act of business activity. The operation must meet the requirements of ACID (Atomicity, Consistency, Isolation, Durability). The set of operations of a single module represents the interface of client-server interaction of this module.

As you can see, this definition is very important for the whole system - it not only connects the user and his business activities with what should be implemented, but also imposes requirements on how the system should be implemented (this is how it was previously defined when designing the architecture ) - business actions within an operation must be within a transaction.

Work on the list of terms was happening all the time. We maintained its fullness, i.e. tried to ensure that the documentation did not have a term that was not defined in this list. In addition, there were cases when we changed the terms. For example, after several months from the beginning of writing the requirements, we decided to replace the Counterparty with the Company. The reason was simple: it turned out that no one was able to use the word "counterparty" in speaking, in conversation. And if so, then it should have been replaced by something more melodic.

Often there were cases when it was necessary to interrupt the discussion and climb into the requirements in order to understand whether the discussed functionality fits the existing definitions. And in order to maintain consistency of requirements, we eventually had to either change the implementation, or adjust the descriptions of the terms.

As a result, we had about 200 business and system definitions in the list, which we used not only in all the documentation, including, for example, the technical design developed by programmers, but also in conversation, during an oral discussion of the functionality of the system.

The second part, on which all the documentation was based, was the description of the business roles.

Description of business roles


Everyone knows that users use the system. But even in a small system, they have different rights and / or roles. Probably the simplest division is the administrator and the ordinary user. In a large role system, there may be several dozens and the analyst needs to think about this in advance and indicate the roles when describing common scenarios (see below) and in the headings of usage scenarios. The list of business roles is used to implement groups and user roles, assign functional rights to them, it is necessary for testers to test scripts under the desired roles.

We did not have to invent the business roles of users, since the company had established departments, roles, and functions. The description of the roles was given at a qualitative level based on an analysis of the basic functions of employees. The final empowerment of roles with specific rights occurred closer to the end of development, when the set of functional rights became stable.

A couple of examples:


Requirement Levels


One of the important concepts that we used in the development of requirements was their division into levels. Alistair Coburn in his book Modern Methods for Describing Functional Requirements for Systems identifies 5 levels. We used 4 - three levels of business requirements plus system requirements:

Business requirements
  1. Common scenarios (corresponds to Cobern’s very white level)
  2. Usage scenarios (corresponds to blue)
  3. Algorithms and checks (rather black)

4. System requirements (no direct equivalent, rather black)

In addition, our requirements were a tree (with cycles). Those. common scenarios were refined by use scenarios, which, in turn, had references to checks and algorithms. Since we used the wiki, the physical implementation of such a structure was not a problem. Use scenarios, algorithms, and validations used objects, their properties, and methods described at the system level.

This methodology allowed us, on the one hand, to describe the current scenario in as much detail as is needed at this level, bringing the details to the lower level. On the other hand, being at any level could go higher to understand the context of its implementation. It was also provided with wiki functionality: scripts and algorithms were written on separate pages, and the wiki allowed to see which pages refer to the current one. If the algorithm was used in several scenarios, then it was necessarily imposed on a separate page. Programmers usually implemented such fragments as separate methods.

The picture below shows a part of our hierarchy (the content will be discussed later).

It is important to note that if the system level described all objects of the system without exception, then the scripts were written not for all cases of user behavior. Indeed, many objects, in fact, were reference books, and the requirements for them are more or less obvious and similar. In this way, we saved analyst time.

An interesting question is, who in the project team needs which of the levels? Future users can read common scripts. But already the use scenarios for them are complex, so the analyst usually discusses the scenarios with users, but does not give them to them for independent study. Programmers usually need algorithms, checks and system requirements. You definitely can respect a programmer who reads usage scenarios. Testers (as well as analysts) need all levels of requirements, because they have to check the system at all levels.

Using the wiki allowed working on the requirements in parallel with all members of the project team. I note that at the same moment different parts of the requirements were in different states: from being in operation to already implemented ones.

Business requirements


Common Scripts


The root page of our requirements tree consisted of common scenarios, each of which described one of the 24 business processes to be implemented in this module. The scenarios on the page were arranged in the sequence in which they were carried out in the company: from the creation of the object with the goods sold to the transfer to the client. Some specific or supporting scripts were placed at the end in a separate section.

A common scenario is a sequence of user and system steps to achieve a specific goal. Descriptions of common scenarios were significantly less formal compared to use scenarios, since they were not intended to be implemented. The main goal of the overall scenario is to summarize the usage scenarios, to rise above the system and see what the user ultimately wants to do, and how the system helps him with this. I want to note that the common scenarios also contained the steps that the user carried out outside the system, since it was necessary to reflect his work in its entirety, with all the steps necessary to achieve the business goal. At this level, the role of the system in the work of an employee of the company is clearly visible, which part of this work is automated and which part is not. It was here that it became clear that some sequence of actions that we proposed to be performed by the user in the system is redundant, that part of the steps can be shortened.

Some other goals of common scenarios are:

Here is an example of one of the common scenarios:


As you can see, only half of the steps are automated, and those are described as briefly as possible. Also from the first step it is clear that manual translation of the print job to the 'In Work' status is superfluous in principle, it is possible to simplify the user's work and automatically translate the job to this status when printing.

The “Print Job” link, indicating the description of the object in the system requirements, is superfluous, since no one needs to jump onto it from the general scenario. But the link “batch printing of documents for cargo” is important - it leads to a use case that formally describes the actions of the user and the system.

Our usage scenarios had the following format:

Usage scenarios


The use case contained numbered steps, which in 99% of cases obviously began with the words User or System . The numbering is important because it allowed in the questions and comments to refer to the desired item. Each step is usually a simple sentence in the present tense. Checks and algorithms were carried out to the next level and often on separate pages in order to simplify the perception of the script, as well as for reuse.

I will cite the usage scenario referenced by the general scenario above.


Often, analysts draw the user interface and based on it write scripts, explaining that so clearer. There is some truth in this, but we held to the position that the interface is the business of the interface designer. First, the analyst describes what should happen, and then the interface designer draws a sketch of a web page or dialogue. In this case, it happened that the script had to be changed. There is nothing terrible in this, because our goal is to design all parts of the system so that it is convenient for the user. In addition, each member of the project team, whether an analyst or interface designer, having specific knowledge and contributing to the common cause, influences the work of other project team members. Only together, by combining efforts, you can get an excellent result.

Algorithms and checks


An interesting problem arose when writing algorithms. The analyst tried to describe them as completely as possible, i.e. include all possible checks and branches. However, the resulting texts turned out to be poorly readable, and, as a rule, some details were still missed (probably, the lack of a compiler affected). Therefore, analytics should describe the algorithm as fully as it is important in terms of business logic; the programmer must provide secondary checks in the code.

For example, consider the simple algorithm below.


The algorithm contains only one check, but it is obvious that when writing the method code, the programmer must implement checks on the input parameters; Throw an exception if the current user is not defined, etc. Also, the programmer can combine this algorithm with algorithms for transitions to other statuses and write a single non-public method. At the API level, the same operations will remain, but they will call a single method with parameters. Choose the best implementation of algorithms - this is just the competence of the programmer.

System requirements


As you know, programming is the development and implementation of data structures and algorithms. Thus, by and large, all that a programmer needs to know is the data structures needed to implement the system, and the algorithms that they manipulate.

When developing the system, we used an object-oriented approach, and since OOP is based on the concepts of class and object, our data structures are class descriptions. The term "class" is specific to programming, so we used the "object". So the object in the requirements is equal to the class in the object-oriented programming language (in parentheses, I note that in a couple of sections of the requirements it was necessary to break out in order to separate the object-class and the object-instance of this class in the text).

The description of each object was located on one wiki-page and consisted of the following parts:

We tried to describe everything that is possible in a tabular form, since the table is more visual, its structure helps streamline the information, and the table is well extensible.

The first table of each object described the attributes of its properties necessary for the programmer to create data structures in the database and implement the object on the application server:

Title
The property name is operated by both the user (for example, “I changed the account number”, Number is a property of the Account object), and the project team. Throughout the documentation, property references were used in the form of simple Object. Property notation, which is obvious to any project participant.

Type of
We used Datetime, Date, Time, GUID, String, Enum, Int, Money, BLOB, Array (), Float, Timezone, TimeSpan. The type was reflected at all levels of the application: at the database level, the application server, in the user interface in the form of code and graphical representation. Each type was given a definition so that their implementation would not raise questions for programmers. For example, the following definition was given to the type Money: contains a real number with an accuracy of 4 decimal places, the number can be negative and positive; simultaneously with the value of the system stores the currency; The default currency is the Russian ruble.

Sign of editable
Yes or No , depending on whether the system allows users to change the value of this property in an editing operation. In our system, this restriction was implemented on the application server and in the user interface.

Sign of the presence of zero
Yes or No , depending on whether the field can contain no value. For example, a Bool type field must contain one of the possible values, and a String type field can usually be empty ( NULL ). This restriction was implemented at the database level and on the application server.

Sign of uniqueness
Yes or No , depending on whether this field is unique. Often, uniqueness is determined on a group of fields, in this case, all the fields in the group had Yes + . This restriction was implemented at the database (index) level and on the application server.

Comment
Description of the field: what it means, what it is for, how it is used. If the value of the property is calculated, then it is indicated explicitly with a description of the algorithm for calculating this value.

In addition to these, there were two more columns that were filled by the programmers of the server side when implementing the object:

Both of these fields are not required, because, for example, the property of an object may not be stored in the database, but be calculated as the sum of the invoice.

I want to once again note that programmers took part in writing requirements. This is important for many reasons. Firstly, in this way programmers were better aware of the requirements, moreover, the requirements became “closer to the body”, and not just some piece of paper written by some analyst. Secondly, the documentation for the API was automatically generated. Third, traceability of the requirements was maintained, i.e. it was always clear whether a particular property was implemented, which became especially important when modifying requirements. Of course, such a methodology required more discipline from programmers, which in fact was a positive factor.

In addition, thanks to these columns, programmers working at different levels of the application could always find a common language, i.e. understand the correspondence between the property of an object in the requirements, the field in the database and the property in the API.

As I already wrote, the tabular view is very convenient for expansion. For example, to describe the initial migration, we had a column with the name of the property of the old system or a data conversion algorithm. We also used special icons to describe what the object looks like in the user interface. One time we had a column for the name of the index in the database, so that programmers do not forget to create them for unique fields. If necessary, you can add a column with the dimension of data types for each property.

Here is a typical description of the properties of our object.


The second table of the object contained a description of its operations and their rights. Each operation in the system had a unique name ( Operation column), but in the user interface (in the menu) operations were displayed under short names ( Short name ). To perform any operation it was necessary to have a certain right ( right ). The Comment column for complex methods contained a description of the algorithm or a link to it or to a more general usage scenario. CRUD operations on all types of objects were standardized here, so algorithms for them were usually not required.

The Name column in the code was again filled in by the programmer, which, like in the description of the object, was necessary for documenting the API, increasing the involvement of programmers in writing requirements and traceability. Below is an example of the description of object operations:


In this section there were also tables describing the transition by status.


In the cells there is a short name of the operation, which translates the initial status to the target. For more complex cases, you had to draw full diagrams.

After installing the system, it must contain certain data. For example, a user with administrative rights or a list of countries according to the all-Russian classifier of countries of the world. This data is described in the Data section.

Everything that did not fit into the standard sections above went to the Additional Information section. For example, we had this information on the connections of this object with the old system.

Summarizing, we can say that the system requirements for the object contained all the necessary information for its implementation by the programmer: the data structure in the database, the description of the domain object, restrictions on the data and methods, algorithms for implementing the methods, data that must be present during installation of the system. The description structure is easy to understand and expandable.

Many will say that such a specification of requirements takes a lot of time and is not needed. To which I will object - but as a programmer, guess what exactly needs to be implemented? Does the phrase “It is necessary to implement the User object” is enough to get working code after some time? How much should I drink tea with an analyst to get data from 40 (we had) user properties? Who, if not an analyst or designer, should make an effort and describe all the objects?

Programming tasks for programmers


After describing how the requirements look, consider an interesting question: how should the tasks for programmers be formulated (confine ourselves to the server part of the multi-tier application)? It turns out that most tasks (not defects) come down to three options:

Typical task 1
Title: Implement such an object.
Task text - link to the page with system requirements for the object.
In such a task, the programmer must:
All this can be done on the basis of the description of the object in the system part of the requirements.The programmer must also supplement the table with the description of the properties with the names of the fields of the database table and the API object.

Typical task 2
Title: Implement such an operation of such an object and the rights to it
. Task text - link to the page with the system requirements for the object.
The programmer finds the operation name and rights on the page, and the link in the Comment column contains algorithms, checks, usage scenarios.

Typical task 3
Title: Adjust the object and / or operation.
This task is necessary in case of changes in requirements. The text of the task contains a description of the changes or a link to the requirements version comparison page.

Tool for writing and managing requirements


As many may have guessed, we used Atlassian Confluence to work with the requirements. I want to briefly list the advantages of this product.

However, there were several problems:


In the end, I would like to thank Vadim Loboda and Artem Karateev for valuable advice and careful review of this article.

Anton Stasevich

Source: https://habr.com/ru/post/245625/


All Articles