THE EVOLUTION OF A COPY PROGRAM - Concordia University

Transcription

THE EVOLUTION OF A COPY PROGRAMBY PANKAJ KAMTHAN1. INTRODUCTIONThis document tells a ‘story’ of the evolution of a program caused by the unforeseenchanges in the requirements [Martin, 2002; Martin, Martin, 2006].Let I be the set of input devices, O be the set of output devices, and let P be the program.Then the story is about the impact on the design of P due to variations in I and O ,where · denotes the cardinality.The moral of the story is that, unless there is adequate preparation for change inadvance, the quality of the design of a program can rapidly deteriorate to the point thatthe loss can become irreversible.2. CONVENTIONThere are certain statements in the rest of the document that are associated with specificgraphical notations.The presence of the ‘dangerous bend’ symbol1 illustrated below should be interpreted asa warning.The warnings reflect a violation of the underlying philosophy of object-oriented design(OOD) aiming for ‘high-quality’, in general, and, by reference, a violation of one or moreobject-oriented design principles (OODP), in particular.1The symbol is an electronic rendering of that shown in [Knuth, 1984].1

The presence of the smiley icon [Sanderson, 1997] illustrated below should be interpretedas a (negative) impact on (solution) quality.3. “SOLID” OBJECT-ORIENTED DESIGN AND PROGRAMMINGThe more science becomes divided into specialized disciplines, the more important it becomes tofind unifying principles.― Hermann HakenSOLID is a mnemonic acronym for five basic principles of object-oriented design andprogramming [Martin, Martin, 2006], summarized in Table 1.AcronymSRPOCPLSPISPDIPOOD PrincipleThe SingleResponsibilityPrincipleStatementA class should have only one reason to change.The Open-ClosedPrincipleA class should be open for extension, but closed formodification.The LiskovSubstitutionPrincipleThe sub-types must be substitutable for their supertypes.The InterfaceSegregationPrincipleA client should not be forced to depend uponoperations that it does not use. Also, an interfacebelongs to a client, not to the hierarchy.The DependencyInversion PrincipleThe abstractions should not depend upon details.The details should depend upon abstractions.Table 1. A collection of object-oriented design principles for classes.3.1. SOLID SCOPEThe default target for SOLID is a new design.2

However, if (1) a design ‘smell’ is discovered, and (2) it is possible to ‘refactor’, thenSOLID, particularly those for classes, can also be used to improve the quality of an old(legacy) design, specifically the readability and maintainability of the source code.3

4. EPISODE I: LE DÉBUTIn its first incarnation, a copy program2 is supposed to accept characters as input from thekeyboard, and provide a copy of them to a printer as output.There are three procedures3 in the copy program. The Copy procedure calls the othertwo, namely the ReadKeyboard that reads characters from the keyboard, and theWritePrinter that writes those characters to a printer.The structure chart and the listing of the copy program are shown in Figure 1 and Listing1, respectively.Figure 1. The design of the first version of the copier program.// Copy Program: Incarnation Ipublic class Copier {public static void Copy() {int c;while((c Keyboard.Read()) ! -1) {Printer.Write(c);}}}Listing 1. The C# source code of the first version of the copy program.2The program is in C#, and could be implemented in one of the other members of the C ‘family’ oflanguages. However, the underlying programming language is not relevant to the discussion.3For the sake of this document, terms such as function, method, module, procedure, routine, sub-program,and other similar constructs, are considered synonymous and therefore interchangeable.4

5. EPISODE II: UN MOIS PLUS TARDThere is passage of time. There is a change in the input device requirements due tointernal demands (coming from inside the organization, such as from otherprogrammers).The copy program should also be able to read characters that are input from the Braillereader. (This is, for example, to support users with visual disabilities, includingblindness.)The program in Listing 1 is not designed for a Braille reader.To accommodate the change in the input device, a Boolean argument is added to theCopy procedure. If True, it reads from the Braille reader; if False, it reads from thekeyboard as before.A change in the interface is not feasible at this stage as, with the passage of time,several other programs use the copy program.To let the copy program know that it must read from the Braille reader, a globalvariable4 along with the ?: (ternary) operator5 are used.The result of accommodating the aforementioned changes is given in Listing 2.4The use of global variables in programs is usually considered ‘poor’ practice because of their nonlocality. For example, a global variable can potentially be modified from anywhere, and any part of theprogram may depend on it. Therefore, a global variable has an unlimited potential for creating mutualdependencies and, in general, addition of mutual dependencies increases structural complexity. The useof global variables also affects adversely the readability and understandability of a program. There areprogramming languages, such as Java, that do not have global variables. (In Java, all variables that are notlocal variables are fields of a class. Hence, all variables are in the scope of either a class or a method.)5The origin of the ?: ternary operator lies in the programming language CPL, introduced in the early1960s [Strachey, 2000]. In C#, if the condition is true, first expression is evaluated and becomes the result;if the condition is false, the second expression is evaluated and becomes the result. In this sense, the ?:ternary operator is similar, but not identical, to the if-then-else clause. It has been pointed out in[Boswell, Foucher, 2012, Pages 73-74] that the ternary operator should be avoided in all but the simplestcases.5

// Copy Program: Incarnation IIpublic class Copier {// Reset Flagpublic static bool BFlag false;public static void Copy() {int c;while((c (BFlag ? Braille.Read() : Keyboard.Read())) ! -1) {Printer.Write(c);}}}Listing 2. The C# source code of the second version of the copy program.6

6. EPISODE III: DEUX MOIS PLUS TARDThere is further passage of time. There is a change in the requirements due to externaldemands (coming from outside the organization, such as from customers).The copy program should also be able to output to the screen.The callers of Copy that want to read from the Braille reader must first set the BFlag toTrue and then call Copy. Upon return of Copy, the caller must reset the BFlag; or elsethe next caller may mistakenly read from the Braille reader rather than from thekeyboard. This is made explicit in a comment.The result given in Listing 3 is a change in design that is similar to Episode II. It requiresyet another global variable and another ?: operator.// Copy Program: Incarnation IIIpublic class Copier {// Reset Flagspublic static bool BFlag false;public static bool SFlag false;public static void Copy() {int c;while((c (BFlag ? Braille.Read() : Keyboard.Read())) ! -1) {SFlag ? Screen.Write(c) : Printer.Write(c);}}}Listing 3. The C# source code of the third version of the copy program.There are a few notable issues in the foregoing change. There is an increase in pressurethat manifests in degradation of quality at both process and product levels.6.1. PROCESSThe design of the copy program given in Figure 1 is not based on software engineeringprinciple of anticipation of change [Ghezzi, Jazayeri, Mandrioli, 2003]. The changesare incorporated in the evolution of design (manifested in Listings 1-3) after requestsfor changing the requirements are received.7

The accommodation of changes is becoming increasingly difficult. This, in turn, islikely to adversely affect productivity. (There is reaction—not anticipation—tochange.)6.2. PRODUCTThe evolution of design is based on ‘patchwork’. The structure of the copy program isbeginning to deteriorate6. In other words, patchwork is adversely affecting thereadability and maintainability of the source code.6For example, further changes to the input device is likely to involve a completely restructuring of thewhile loop conditional.8

7. EPISODE IV: LA LEÇONThe top-down design of the copy program given in Figure 1 has issues.It is inflexible because of the direction of its dependencies. The high-level Copyprocedure depends directly on the low-level details of the ReadKeyboard and theWritePrinter procedures. Thus, a change in the low-level details affects the highlevel policy.Board Time!Give the meaning of the Domino Effect7.Therefore, a completely new approach to the original design is required, such that thechange is transparent to a user. The new design has the following characteristics: By following the Open-Closed Principle (OCP), an abstract class is included forabsorbing the input. The possibility of a new input device can now be accommodatedwithout modifying the copy program. By following the Dependency Inversion Principle (DIP), the dependency from theCopy procedure to the input device is inverted. The STRATEGY pattern [Gamma,Helm, Johnson, Vlissides, 1995; Shalloway, Trott, 2005, Chapter 9; Martin, 2014,Chapter 7; Shvets, 2015; Shvets, 2019] is used to create the desired inversion.(The STRATEGY pattern is also known as the POLICY pattern, and is aligned withthe OCP and the DIP.)The result of recasting Listing 1 (by refactoring to a pattern) is shown in Listing 4.7A domino effect “is the cumulative effect produced when one event sets off a chain of similar events”[Wikipedia].9

// Copy Program: Incarnation IV// Open for Extension, Closed for Modificationpublic interface Reader {int Read();}// Program to an Interface, Not an Implementationpublic class KeyboardReader : Reader {public int Read() {return Keyboard.Read();}}public class Copier {public static Reader reader new KeyboardReader();public static void Copy() {int c;while ((c (reader.Read())) ! -1) {Printer.Write(c);}}}Listing 4. The C# source code of the first version of the copy program based on SOLID.7.1. OBSERVATIONSObservation [Detect, Diagnose, Solve]. The new design is based on interplay betweenthree aspects: (1) detecting the problem by following certain agile practices, (2)diagnosing the problem by applying design principles, and (3) solving the problem byapplying an appropriate design pattern8.There are known knowns. These are things we know that we know. There are known unknowns.That is to say, there are things that we know we don’t know. But there are also unknownunknowns. There are things we don’t know we don’t know.— Donald RumsfeldObservation [Design for Change: Revisited]. The causes (or origins) of a change indesign are not always in the control of a designer and may not always be known to adesigner. It is better to focus on making a design ‘change-proof’ rather than focus onthe causes of a change in design.8In the STRATEGY pattern, the behaviors of a class are not inherited, but encapsulated using interfaces.The behaviors are defined as separate interfaces, and specific classes that implement and encapsulatethese interfaces. This allows better decoupling between the behavior and the class that uses the behavior.The behavior can be changed without ‘breaking’ the classes that use it. (Source: Wikipedia.)10

Therefore, instead of considering the causes of redesign, it is better to consider thethings in the design that vary (that is, things that can be changed without redesign)[Shalloway, Trott, 2005, Chapter 9; Stuurman, 2015]. The things that vary can then beencapsulated.Resisting premature abstraction is as important as abstraction itself.― Robert C. MartinObservation [Anticipation of Change: Revisited]. Listing 4 is protected from thevariations in different input devices, but not from different output devices. Thisdecision is intentional.The design does not need to get inflated by overzealous preemption9 that is based onprediction. In other words, anticipation of change is not identical to ‘bloating’. Thepoint is that if such a protection is needed, then it can be added easily later.Mobile Intermezzo! Use the Web to search for “Gold Plating”. Use the Web to search for “YAGNI”.Observation [Quality]. In general, in the current computing environment,maintainability is considered more important than space efficiency. This isparticularly the case in an era in which the concerns of memory and disk size havebecome secondary due to low production and purchasing cost10. This, however, does notmean wasting space (and, thereby, violating one of principles of lean softwaredevelopment [Gehtland, Tate, 2004, Section 1.3; Shmueli, Ronen, 2017]. In other words,by the previous observation, space efficiency need not be sacrificed for the sake ofmaintainability.Figure 2 shows the results of a survey [Stevenson, Wood, 2018] in which a collection ofpractitioners were asked about the relative significance they place on the practice of“Program to an Interface” [Stuurman, 2015, Section 1.2.5].9There may be input and output devices that are not even known at the time the program is written.Therefore, any attempt of trying to ‘exhaust’ all possibilities is likely to be futile. This is a mild realizationof You Ain’t Gonna Need It (YAGNI), a maxim of Extreme Programming (XP) [Beck, 2000].10This is in stark contrast to the time of inception of UNIX and C.11

Figure 2. The relative significance given by practitioners to “Program to an Interface”.(Source: [Stevenson, Wood, 2018].)7.2. IMPROVEMENT IN PERSPECTIVEтеория решения изобретательских задач OR TEORIYA RESHENIYAIZOBRETATELSKIKH ZADATCH (TRIZ) OR “I NEVER PROMISED YOU AROSE GARDEN”The quality of Listing 4 is not unconditionally or universally ‘superior’ to Listing 1.Indeed, the size of Listing 4 (for example, using one of the basic source code metrics forlength) is greater than Listing 1. Listing 4 may also be perceived as less readable thanListing 1.However, the overall benefits of Listing 4 outweigh the costs of Listing 1.12

8. CONCLUSIONI am prepared for the worst, but hope for the best.― Benjamin Disraeli[I am] hoping for the best, prepared for the worst, and unsurprised by anything in between.― Maya AngelouInvest in the abstraction, not the implementation. Abstractions can survive the barrage ofchanges from different implementations and new technologies.― Andrew Hunt and David ThomasThere are a few general conclusions that can be drawn from the evolution of the copyprogram: Requirements Change. The requirements are in a state of constant flux. This shouldbe accepted as a fact. Indeed, agile methodologies such as Extreme Programming(XP) “embrace change” rather than resist change [Beck, 2000]. Agile Design. The responsibility for degradation of design does not (solely) liewith the changes in the requirements. The design should (as far as possible) be agile,flexible, immune, invariant, resilient, and potentially a hallmark of other pseudosynonymous adjectives. Pessimistic Forethought. The approach to design for change needs to be proactive,not reactive. The design should not be based on the best case scenario, but on a(reasonably concluded) worst case scenario. In general, software engineering is notabout optimism or pessimism, but pragmatism.ACKNOWLEDGEMENTThe inclusion of images from external sources is only for non-commercial educationalpurposes, and their use is hereby acknowledged. In particular, the author is grateful toRichard J. Kinch for the use of the ‘dangerous bend’ symbol, and David W. Sandersonfor the smiley icon.13

REFERENCES[Beck, 2000] Extreme Programming Explained: Embrace Change. By K. Beck. AddisonWesley. 2000.[Boswell, Foucher, 2012] The Art of Readable Code. By D. Boswell, T. Foucher.O’Reilly Media. 2012.[Gamma, Helm, Johnson, Vlissides, 1995] Design Patterns: Elements of ReusableObject-Oriented Software. By E. Gamma, R. Helm, R. Johnson, J. Vlissides. AddisonWesley. 1995.[Gehtland, Tate, 2004] Better, Faster, Lighter Java. By J. Gehtland, B. A. Tate. O’ReillyMedia. 2004.[Ghezzi, Jazayeri, Mandrioli, 2003] Fundamentals of Software Engineering. By C.Ghezzi, M. Jazayeri, D. Mandrioli. Second Edition. Prentice-Hall. 2003.[Knuth, 1984] The TEXbook. By D. E. Knuth. Addison-Wesley. 1984.[Martin, 2002] Agile Software Development: Principles, Patterns, and Practices. By R. C.Martin. Prentice-Hall. 2002.[Martin, 2014] Agile Software Development: Principles, Patterns, and Practices. By R. C.Martin. Pearson Education. 2014.[Martin, Martin, 2006] Agile Principles, Patterns, and Practices in C#. By R. C. Martin,M. Martin. Prentice-Hall. 2006.[Sanderson, 1997] Smileys. By D. W. Sanderson. O’Reilly Media. 1997.[Shmueli, Ronen, 2017] Excessive Software Development: Practices and Penalties. By O.Shmueli, B. Ronen. International Journal of Project Management. Volume 35. 2017.Pages 13-27.[Shalloway, Trott, 2005] Design Patterns Explained: A New Perspective on ObjectOriented Design. By A. Shalloway, J. Trott. Second Edition. Addison-Wesley. 2005.[Shvets, 2015] Design Patterns Explained Simply. By A. Shvets. SourceMaking. 2015.14

[Shvets, 2019] Dive Into Design Patterns. By A. Shvets. SourceMaking. 2019.[Stevenson, Wood, 2018] Recognising Object-Oriented Software Design Quality: APractitioner-Based Questionnaire Survey. By J. Stevenson, M. Wood. Software QualityJournal. Volume 26. 2018. Pages 321-365.[Strachey, 2000] Fundamental Concepts in Programming Languages. By C. Strachey.Higher-Order and Symbolic Computation. Volume 13. 2000. Pages 11-49.[Stuurman, 2015] Design for Change. By S. Stuurman. Ph.D. Thesis. Open University.Heerlen, The Netherlands. 2015.15

This resource is under a Creative Commons Attribution-NonCommercialNoDerivatives 4.0 International license.16

programming languages, such as Java, that do not have global variables. (In Java, all variables that are not local variables are fields of a class. Hence, all variables are in the scope of either a class or a method.) 5 The origin of the ?: ternary operator lies in the programming language CPL, introduced in the early 1960s [Strachey, 2000].