Software engineering is the process of systematic application of different engineering approaches to develop software. The engineering approach applied in software is equivalent to the approach taken across all other engineering disciplines. Engineering approaches in software include user requirement identification, design of software, software development, quality assurance and maintenance.
Sharing ideas via human interaction is critical to any engineering discipline and engineering teams use different methods to ensure a successful thought transfer process amongst stakeholders. These methods are used to create data sharing and storing standards, set up best practices around any engineering approach, roll-out formal procedures and carry out accreditations.
Software engineering teams use diagrams with fixed notations to denote ideas without using words to store and transfer knowledge while mapping requirements to software. Diagram-based knowledge transfer is used when the diagram notations are correctly applied with formal agreements between engineers. Similarly, building a common vocabulary about the requirement and solution is important. The use of common vocabulary must transfer knowledge and explain the requirement comprehensively without sacrificing intent.
Software users within an organization outline their requirements in the form of human language; commonly, business and engineering teams would engage in a series of discussions and the content will be documented. In contrast, software is developed using computer-specific language(s) and software engineers tackle language translation through design.
Engineering teams would begin solution development by first dissecting the requirements outlined by the business in order to get a thorough insight and understanding of what the software solution would potentially look like. Typical software requirements are made up of collections of inputs, actions and outcomes. Therefore, the first attempt is to create a bridge between requirements and the primitive constructs of software language by building intermediary constructs in a way that the business user and the program can understand. The engineering teams need to build software objects that are meaningful to the user by including inputs found in the requirement. Thereafter, the engineering teams will need to build software operations as meaningful actions to the user. Finally, the requirement outputs are designed as software objects by the team.
It becomes easy to analyze and confirm user requirements once the correct intermediary constructs become verifiable by the user. Thereafter, the constructs become the vehicle of communication between users and the engineering teams throughout the software development process and the constructs become the vocabulary of the software. Furthermore, various parts of the software are associated with different types of business users so it becomes essential to build independent vocabularies to represent different user requirements and user types. For example, sales executives deal with pro forma invoices while accountants deal with invoices. The engineering teams must identify these different invoices as independent objects.
Software design is the process of building intermediary language constructs or vocabularies. Modern software engineering teams are able to progressively improve software design with each software delivery cycle. It is important to note that it is best to plan for shorter delivery cycles to enable an evolution of the design with every delivery cycle.
Engineering teams can thus start thinking about how to create an excellent design before even embarking on development. An example of progressive evolution of software design is given below: The Agile story is a user requirement obtained from a medical records management system for family practitioners.
“As a family doctor, I administer flu vaccines in standard and high dosages to both child and adult patients after dosage strength preparations. A patient can receive the flu vaccine every six months. I need to record this information so that I can identify which patients are in need of vaccination.“
A typical software development team using object-oriented software design techniques would create a design like the following to cater to the requirement.
The design considers the viewpoints of the engineering team and business user interchangeably. The doctor (business user) may not understand the design depicted due to lack of technical know-how. The challenge is then to simplify the design into something that the doctor scan understands. The bold text in the design will be changed to match the requirements and vocabulary specified in the Agile Story in the next two design iterations. These subsequent iterations will include a new vocabulary that both the doctor and software engineering team understand.
The abstractions in the above design are typical object-oriented notions and notations; however, these abstractions do not reflect the more detailed aspects of the user requirement. For example, the design does not include the dosage requirement based on patients age, the method for preparing vaccines, the norm of administering a vaccine to a patient every six months and the classification of vaccinated vs. non-vaccinated patients. Since the design lacks these abstractions, it may not be helpful to the doctor. The design captures a couple of requirement notions – the ‘Doctor’ and the ‘Vaccine’ – as objects. These two objects are the most primitive vocabularies of the design.
Software engineers communicate with business users, but they are also required to communicate with team members in order to explain the design. The constructs of the initial design depicted above does not serve this purpose; team members will not understand the requirement directly from the design constructs which includes a set of object-oriented notions and notations. Therefore, the only avenue available to understand the requirement is to refer to the Agile Story.
The next iteration is a slightly enhanced version.
Consider the bold text: some of the object-oriented notions visible in the first design are absent from the second design. It now depicts a process in which a doctor administers a vaccine (administersFluVaccine) and retrieves a patient’s vaccinations history (findFluAdministration). The text (in italics) is part of the new vocabulary, which is common to both the Agile Story and the software design. The design has improved, and software engineers are able to understand it better; nevertheless, this version of the design is also unsatisfactory in terms of communication between the user and software engineer.
The final version includes the entire vocabulary specific to the requirement.
The second version of the design included the findFluAdministration vocabulary. The software engineers learnt that the findFluAdministration operation is meaningless in the context of the Agile Story. There is no need for a doctor to see all patient vaccines as outlined in the Agile Story. Also, a doctor would find it challenging to relate to the term `find`, and hence would not understand the findFluAdministration operation. `Find` is a keyword used by software engineers to denote an operation that locates specific records in databases based on a given criteria. In the Agile Story, doctors need to classify the patients as vaccinated or non-vaccinated to be able to determine if a patient can be administered a vaccine at a given moment. Therefore, the proper vocabulary in this scenario would be fluVaccineCanBeAdminsteredTo. In this operation, the system uses onNextVaccinateDate as an input as depicted.
The next step in the process is to integrate the dosage variation based on the patients age into the design (standardAdultFluDosage, standardChildFluDosage, highAdultFluDosage,highAdultFluDosage). Refer again to the bold text: a new construction placeholder called Vaccines helps integrate this missing notion into the design. This construction placeholder defines all dosage variations by the patient’s age.
As the final step, it is necessary to include the notion of vaccine preparation by the doctor. The vaccine preparation must take place prior to administering the vaccine to a patient. This latest design should now give doctors the full understanding of what, when, and how, software handles the original requirement (Agile Story).
The process of creating an ideal design with the right vocabulary to facilitate effective communication between a business user and an engineer is not straightforward and requires added effort from the software engineering teams. There are a few empirical studies classifying the types of software that need detailed designs. Findings from these studies can help reduce the design effort in software development projects, and illustrate the importance of comprehensive design in the following situations:
- If the software has more than 30 User Stories.
- If business users think the software requirements will change in the future.
- If engineers think the software has room to grow after extended use.
- If engineers in the software development team are new to the domain.
The book “Domain-Driven Design Distilled” by Vaughn Vernon is an excellent source for software engineers who wish to analyze these concepts further.
In conclusion, it is important to note that the design should constantly evolve along with the requirements elicitation process. Software engineers must review the design with actual business users and progressively enhance the design to avoid any mismatch between the requirement specification (Agile Story) and the actual software.
About the Author
Lahiru Karunatilake has more than 20 years of experience in Software Engineering and Engineering Best Practices and is currently Director – Engineering & Architecture at Sysco LABS Sri Lanka. He leads Research & Development in Engineering, Agile Team Enablement and defines Engineering Best Practices to be followed across the organization including training Engineers in areas like Domain Driven Design.