BIS301 Reliable Programming 2023 PDF

Summary

These are lecture notes for BIS301 Reliable Programming in 2023. The notes cover topics such as system analysis and design, and the lecturer's notes borrow material from Ian Sommerville.

Full Transcript

BIS301 An Awesome Introduction to System Analysis and Design Some contents of the lecture notes are taken from Ian Sommerville...

BIS301 An Awesome Introduction to System Analysis and Design Some contents of the lecture notes are taken from Ian Sommerville Reliable Programming © BIS301 2023 Reliable Programming © BIS301 2023 Software quality Creating a successful software product does not simply mean providing useful features for users. You need to create a high-quality product that people want to use. Customers have to be confident that your product will not crash or lose information, and users have to be able to learn to use the software quickly and without mistakes. Reliable Programming © BIS301 2023 3 Figure Figure 8.1 Software product 8.1 attributes quality Product quality attributes Reliability Availability Security Resilience Product quality attributes Usability Maintainability Responsiveness Reliable Programming © BIS301 2023 4 Programming for reliability There are three simple techniques for reliability improvement that can be applied in any software company. Fault avoidance You should program in such a way that you avoid introducing faults into your program. Input validation You should define the expected format for user inputs and validate that all inputs conform to that format. Failure management You should implement your software so that program failures have minimal impact on product users. Reliable Programming © BIS301 2023 5 Figure 8.2 Underlying causes of program errors Figure 8.2 Underlying causes of program errors Programmers make mistakes Programmers make mistakes because they don’t properly because they use unsuitable understand the problem or the technology or they don’t application domain. properly understand the technologies used. Problem Technology Programming language, libraries, database, IDE, etc. Program Programmers make mistakes because they make simple slips or they do not completely understand how multiple program components work together and change the program’s state. Reliable Programming © BIS301 2023 6 Figure 8.3 Software complexity Figure 8.3 Software complexity The shaded node interacts, in some ways, with the linked nodes shown by the dotted line Reliable Programming © BIS301 2023 7 Program complexity Complexity is related to the number of relationships between elements in a program and the type and nature of these relationships The number of relationships between entities is called the coupling. The higher the coupling, the more complex the system. The shaded node in Figure 8.3 has a relatively high coupling because it has relationships with six other nodes. A static relationship is one that is stable and does not depend on program execution. Whether or not one component is part of another component is a static relationship. Dynamic relationships, which change over time, are more complex than static relationships. An example of a dynamic relationship is the ‘calls’ relationship between functions. Reliable Programming © BIS301 2023 8 Types of complexity Reading complexity This reflects how hard it is to read and understand the program. Structural complexity This reflects the number and types of relationship between the structures (classes, objects, methods or functions) in your program. Data complexity This reflects the representations of data used and relationships between the data elements in your program. Decision complexity This reflects the complexity of the decisions in your program Reliable Programming © BIS301 2023 9 Table 8.1 Complexity reduction guidelines Structural complexity Functions should do one thing and one thing only Functions should never have side-effects Every class should have a single responsibility Minimize the depth of inheritance hierarchies Avoid multiple inheritance Avoid threads (parallelism) unless absolutely necessary Data complexity Define interfaces for all abstractions Define abstract data types Avoid using floating-point numbers Never use data aliases Conditional complexity Avoid deeply nested conditional statements Avoid complex conditional expressions Reliable Programming © BIS301 2023 10 Ensure that every class has a single responsibility You should design classes so that there is only a single reason to change a class. If you adopt this approach, your classes will be smaller and more cohesive. They will therefore be less complex and easier to understand and change. The notion of ‘a single reason to change’ is, I think, quite hard to understand. However, in a blog post, Bob Martin explains the single responsibility principle in a much better way: Gather together the things that change for the same reasons. Separate those things that change for different reasons.* Reliable Programming © BIS301 2023 11 Figure 8.4 The DeviceInventory class Figure 8.4 The DeviceInventory class DeviceInventory DeviceInventory laptops laptops tablets tablets phones phones device_assignment device_assignment addDevice addDevice removeDevice removeDevice assignDevice assignDevice unassignDevice unassignDevice getDeviceAssignment getDeviceAssignment printInventory (a) (b) Reliable Programming © BIS301 2023 12 Adding a printInventory method One way of making this change is to add a printInventory method, as shown in Figure 8.4 (b). This change breaks the single responsibility principle as it then adds an additional ‘reason to change’ the class. Without the printInventory method, the reason to change the class is that there has been some fundamental change in the inventory, such as recording who is using their personal phone for business purposes. However, if you add a print method, you are associating another data type (a report) with the class. Another reason for changing this class might then be to change the format of the printed report. Instead of adding a printInventory method to DeviceInventory, it is better to add a new class to represent the printed report as shown in Figure 8.5. Reliable Programming © BIS301 2023 13 Figure 8.5 The DeviceInventory and InventoryReport classes gure 8.5 The DeviceInventory and InventoryReport classes DeviceInventory InventoryReport laptops tablets report_data phones report_format device_assignment updateData addDevice updateFormat removeDevice print assignDevice unassignDevice getDeviceAssignment Reliable Programming © BIS301 2023 14 Avoid deeply nested conditional statements Deeply nested conditional (if) statements are used when you need to identify which of a possible set of choices is to be made. For example, the function ‘agecheck’ in Program 8.1 is a short Python function that is used to calculate an age multiplier for insurance premiums. The insurance company’s data suggests that the age and experience of drivers affects the chances of them having an accident, so premiums are adjusted to take this into account. It is good practice to name constants rather than using absolute numbers, so Program 8.1 names all constants that are used. Reliable Programming © BIS301 2023 15 YOUNG_DRIVER_AGE_LIMIT = 25 OLDER_DRIVER_AGE = 70 ELDERLY_DRIVER_AGE = 80 YOUNG_DRIVER_PREMIUM_MULTIPLIER = 2 OLDER_DRIVER_PREMIUM_MULTIPLIER = 1.5 ELDERLY_DRIVER_PREMIUM_MULTIPLIER = 2 YOUNG_DRIVER_EXPERIENCE_MULTIPLIER = 2 NO_MULTIPLIER = 1 YOUNG_DRIVER_EXPERIENCE = 2 OLDER_DRIVER_EXPERIENCE = 5 def agecheck (age, experience): # Assigns a premium multiplier depending on the age and experience of the driver multiplier = NO_MULTIPLIER if age