1. Identifying buttons 2. ParseInputController 3. The rest of the system heavily depends upon them. These classes don�t depend much on other classes apart from themselves.Put classes such as ProofItems, ProofBox, Proofline, ProofWindow, View in another package 4. 5. Byte serialization is not meant for long term. If new version of Raptor is released and any changes are made to the internal structure of the ProofBox classes, then the old save file wouldn�t work. 6. Remove parseinputcontroller and put its methods inside relevant classes. (ProofWindows)
To add a new rule must change code in the following places: Raptor.ProofWindow.actionPerformed Raptor.ProofWindow.getProofToolbar Raptor.RuleController.getNDRUle Raptor.RuleController.getRAPRule() Raptor.Help.HelpMessages() Difficulty to add to GUI: Raptor.ProofWindow.actionPerformed(ActionEvent)
What�s bad about duplicated codes? Code duplication is undesirable as it causes update anomaly and makes understanding codes difficult. Slight variations in two different codes are also hard to distinguish as well. ///////////////////////////// Why do they do it? However, people still do them because of their lazyness, and using just copy and paste and with the thought of that, this code works so I should just reuse it. ////////////////////////// Duplication in Raptor: There are numerous places with code duplications. I used a program call CodeAnalytix to search for them. It generates the whole list of the places code are duplicated, and show them on the screen for comparison. The 4 types of code duplication found in Raptor include: // Same code in same class 1) 51..53 lines in ProofWindow(x2) Having the same code in two places in the same class, with only differences in its parameter values as shown in this diagram. Here, this part of the duplicated code handles the situation where the user wants to add a given/ precondition for a proof in Pandora, and the other is for RaptorWhat should be done is to refactor them into a subroutine and allow us to pass the parameter values in as arguments. More example 36..38 lines in RaptorView(x2) (272, 369) Same code for the action "Edit a method", "save a method" difference is just a boolean paramter for setUpMethodFrame(true, true) and setUpMethodFrame(true, false) /////////////////////////// // Same code in different classes 2) 107..119 lines in PandoraView,RaptorView, (552, 1765) Having the same code in two different classes � in Raptor / Pandora view, which creates the same menu bar, i.e save , load, export to latex. This could be separated into a different package that handles the menu bar initialization, and again, allow us to inject the parameters to customize the menu bar. Or add to parent class, View More Example 22..24 lines in PandoraView, RaptorView, 179, 703 Code that handles the event when "example" / "example/proof" is pressed /////////////////////////// // Duplicated Code in subclasses when overriding abstract method of superclass 3) 16 lines, Pandora ProofWindow, RaptorProofWindow 145, 201 Another type is of code duplication is found when methods of superclass is overridden by subclasses. An example is inputProofMode() in ProofWindow which is an abstract class. The two subclasses, RaptorProofWindow and PandoraProofWindow have the same code for the creation of the buttons �Start Proof�and �Solve Proof Mode� Solve it by moving to superclass More Example 30..31 lines in Pandora ProofWindow, RaptorProofWindow 528, 828 Same codes used to set the contents of the siganture toolbar /////////////////////////////////////////////////// //Same codes for an overidden method in subclass and its super class method. 4) 16 lines, View and RaptorView RaptorView inherits applyfont() method but overrides it with the same code. Can be fixed by just removing the method from RaptorView
Introduction - Problems with current saving system: According to the author, it�s not meant for long term storage. This is because, if any changes in the internal structure of classes are made (i.e adding or removing fields) then deserialization will fail. 2. According to Java API, some classes will not be compatible with future version of Swings, and they encourage users to shift to using XML instead. How could XML improve the storage of a proof? 1.No dependencies on the private implementation of the stored class, as XML stores the steps needed to recreate objects and setting the property values through its public APIs i.e setters and getters 2.Non structural errors like missing methods doesn�t terminate the loading sequence. It will detect the missing method, generate warnings and continue to load in the unaffected parts. 3.Easier for human to read, so when problems occur, can open up XML files to read. How to implement this new feature? 1. 2. XMLEncoder stores the steps needed to recreate the object that is being serialized. This task is given to the PersistenceDelegate. XMLEncoder and PersistenceDelegate is easiest to set up if the object follows Java Beans specification. But but ProofBox doesn�t follow the java beans specification as it lacks zero-argument constructer, some getters and setters, 2 ways to do this. 1 way is to rewrite ProofBox so it follows Java Beans specs, so for each property, there should get a get and a set method, and have a zero-argument constructor. Then XMLEncoder would handle the writeObject automatically. 2nd way is, since ProofBox doesn�t follow Java Beans, then PersistenceDelegate effectively doesn�t know about the ProofBox object. We need to customize it such that it knows exactly which constructor to call to recreate the object, which argument to pass into the constructor, which methods to use to get or set property values. 3. Next question is how to deal with Redo/Undo stack. When we finished setting up the customized PersistenceDelegate, it becomes simple as we can store the states of the undo/redo list by iterating through each list, and for each ProofBox in the list, write out statements to the encoder to use the specific APIs to recreate that ProofBox. Version changes, suppose add in new variables, what to do? If they follow java beans specs, with getters / setters, XML Encoder would query all the getters and able to store the values automatically.
- Stovepipe System: Cannot differentiate the whole of Pandora and Raptor due to tight coupling. Cannot differentiate modules which only handle GUI related stuff such as View, Entry, ProofWindow etc from the rest of the system. Difficult for future extension. Solution: layer nicely and remove any dependencies going upwards. - Call Super: Most of the actionPerfomred() methods have implemented this anti-pattern. Solution: create abstract methods that the sub classes must implement to perform additional actionEvent handling. These methods will be then called from the super classes actionperformed() and take advantage of polymorphism; - Circular Dependency: Circular dependencies amongst software modules. Circular dependencies exist between (Raptor-NDRules), (Raptor-ProgramParser), (Raptor,LogicParser). Solution: use interfaces; mainly abstract client and abstract server to decouple classes; thus possible to decouple packages. - God Object: The following four classes are considered as fat. ProofWindow, RaptorView, ProofBox and RaptorProofWindow. These classes do a lot of stuff. I presume, �RaptorProofWindow� object would be considered as a god object looking at the amount of work it carries out alone. RaptorView can be considered as well. Solution: Extract all functionalities which are not directly related to proof window and frames from Raptor/PandoraProofWindow and Raptor/PandoraView. Make smaller classes to handle them. - Sequential Coupling: Example: Can� call rapctrl.apply() before rpctrl.initialise(). If not called in order it breaks. Solution: Write defensive code, usually check for null before going forward. Should call initialize inside apply or in the constructor. RAPRuleController rapctrl = new RAPRuleController(rule, line); rapctrl.initialise(); try{ rapctrl.apply(); � } - Poltergeist: RapRuleController and NDRuleController fall in this anti-pattern. Poor object design (Short living, sole purpose is to call methods on other more permanent objects). Solution: RapRuleController created by RuleController�s ProgSelectState. NDRuleController created by RuleController�s NDSelectState. Both of them apply a specific rule to a given line. This can be written in the states themselves. - Magic Number: RaptorView and ProofWindow contain code where it uses raw numbers. Solution: Define these numbers as constants with meaningful names. Can use enums for identifying individual components // Enable the "Done" and "Cancel" buttons and enable the "Help" eb.getComponent(numcomponents - 1).setEnabled(true); eb.getComponent(numcomponents - 3).setEnabled(true); JMenu menu = (JMenu) menuBar.getComponent(2); - Magic String: All the actionEvents are handled using labels and String comparison. Look at actionPerformed(). Solution: Weili�s proposed methods for identifying commands and using actionListeners. - Copy and Paste Programming: We can use tools find all occurrences. Solution: This mainly happens when overriding functions of its super class. Solution: Move duplicate code in the super class and use polymorphism. - Inappropriate Intimacy: Ex: RapRule objects, there are dependencies on other classes on implementation detail. - Feature Envy: NDRuleController and RapRuleController can fall in this category as they make more use of features of other objects than itself. (Needs thorough review whether this can fall as Spaghetti-Code anti-pattern) - Big Ball of Mud: This is because classes are packaged incorrectly and fail to distinguish various abstractions of the system. Everything is dependent on everything else. The dependency flow cannot be used to understand how the system works. (We still require solid examples) - Object Orgy: Unrestricted access to internals; if variable name changes have to replace everywhere. Solution: Write Accessors and make the variable protected/private Example: Inside ProofBox : Line 77 if (pParentWindow.mainProofBox != null) { invCount = pParentWindow.mainProofBox.invCount; unknownCount = pParentWindow.mainProofBox.unknownCount; skolem = pParentWindow.mainProofBox.skolem; } - Spaghetti-Code: Flow of control is jumped from actionPerformed() in ProofWindow and View objects. One method implementation handles majority of flow control. (Needs thorough review whether this can fall as Spaghetti-Code anti-pattern)
Save bug: Sometimes it doesn�t save when you click save. Sometimes it only saves with you quit the program and choose to save. 1) Start Proof 2) Precondition: int x : v_x = 1 3) Program: x = x + 1 4) Postcondition v_x = 2 5) Tick 1-3 and make it go green 6) Tick 7-9 and make it go green 7) File->Save 8) File->Exit 9) Press Yes 10) When it asks to save again, press cancel 11) Restart app 12) Open existing proof Colourize the label: It would be good to have ProofLines in different colour to distinguish between the ones you can press and the ones you can�t. Changes after reloading proof: Currently when loading a saved proof, after you undo you can�t the changes to it. It would be nice to be able to undo and use other methods to prove after loading a file. Syntax errors: When setting the pre, program post condition, if the syntax is wrong then an error message is generated on the textboxes. We have to delete them ourselves before fixing the syntax. It would be nice if the errors appear as pop-ups instead.