Final
Dependency Breaking - Introduce Instance Delegator
- to substitute some other behavior when the static method called
Seeing Responsibilities
1) Group Methods Look for similar method names. Write down all of the methods on the class along with their access types and try to find the ones that seem to go together 2) Look at hidden methods Pay attention to private and protected methods. If a class has many of them, it often indicates that there is another class in the class dying to get out. 3) Look for decision that can change. - Look for decisions, not decisions that you're making in the code, but the decisions that you've already made. Is there some way of doing something (talking to a database, talking to another set of objects, and so on) seems hard-coded? Can you imagine it changing? 4) Look for internal relationships Look for relationships between instance variables and methods. Are certain instance variables used by some methods and not others. 5) feature sketches, show which methods and instance variables each method in the class uses. are great for mapping the internal structure of classes 6) Look for Primary Responsibility Try to descrive the responsibility of the class in a single sentence. 7) When All else fails, do some scratch refactoring 8) Focus on the current work Pay attention to what you have to do right now. If you're providing different way of doing anything, you might have identified a responsibility that you should extract and allow substituting for.
A Heuristic for Writing Characterization Tests
1) Write tests for the area where you will make your changes. Write as many cases as you feel you need to understand the behavior of the code 2) After doing this, take a look at the specific things you're going to change and attempt to write tests for those 3) If you are attempting to extract or move some functionality, write tests that verify the existence and connection of those behaviors on a case-by-case basis. Verify that you are exercising the code that you're going to move and that is connected properly. Exercise conversions.
test-driven development
A development process that consists of writing failing test cases and satisfying them one at a time. As you do this, you refactor to keep the code as simple as possible. Code developed using TDD has test coverage, by default.
free function
A function that is not part of any class. In C and other procedural languages, these are just called functions. In C++ they are called non-member functions. Free functions don't exist in Java and C#.
The case of undetectable side effects
A method should be a command or query but not both. When we have a refactoring tool, we can easily extract on a class and then start to identify groups of methods that can be moved to new classes. Safety first, after the tests are in place, you can make the code much cleaner
pinch point
A narrowing in an effect sketch that indicates an ideal place to test a cluster of features.
link seam
A place where you can vary behavior by linking to a library. In compiled languages, you can replace production libraries, DLLs, assemblies, or JAR files with others during testing to get rid of dependencies or sense some condition that can happen in a test.
object seam
A place where you can vary behavior by replacing one object with another. In object-oriented languages, you usually do this by subclassing a class in your production code and overriding various methods of the class.
seam
A place where you can vary behavior in a software system without editing in that place. For instance, a call to a polymorphic function on an object is a seam because you can subclass the class of the object and have it behave differently.
Interception Points
A point in your program where you can detect effects of a particular change. In general, it is a good idea to pick interception points that are very close to your change points. The first reason is safety. Furthermore, it is often harder to setup tests at distant interception. In most cases, the best interception point we can have for a change is a public method. However, it could be more efficient to start out by trying to find a higher-level interception point. As a result, we could have less dependency breaking to do, and we're also holding a bigger chunk in the vise. With tests that characterize this group of classes, we have more cover for refactoring. A pinch point is a narrowing in an effect sketches, a place where it is possible to write tests to cover a wide set of changes
feature sketch
A small hand-drawn sketch that shows how methods in a class use other methods and instance variables. Feature sketches can be useful when you are trying to decide how to break apart a large class.
effect sketch
A small hand-drawn sketch that shows what variables and method return values can be affected by a software change. Effect sketches can be useful when you are trying to decide where to write tests.
testing subclass
A subclass made to allow access to a class for testing.
unit test
A test that runs in less than 1/10th of a second and is small enough to help you localize when it fails.
characterization test
A test written to document the current behavior of a piece of software and preserve it as you change its code.
programming by difference
A way of using inheritance to add features in object-oriented systems. It can often be used as a way to get a new feature into the system quickly. The tests that you write to provoke the new feature can be used to refactor the code into a better state afterward.
Which of the following are possible ways (whether recommended or not) to get access to test a private method as discussed in the text? Select one or more: a. in some languages like Java, use reflection to temporarily modify the method's visibility b. make the method protected and write a test in a subclass c. move the method to another class and make it public there d. make the method public
ALL make the method public, move the method to another class and make it public there, make the method protected and write a test in a subclass, in some languages like Java, use reflection to temporarily modify the method's visibility
Wrap Class
Add new behavior into a system without adding it to an existing class Could be wrapped with Decorator
Dependency Breaking - Extract Interface
At some point, you might want Domain Model class (such as Account) to be an interface. If you do, you can create a subclass underneath it, push down all of the data and methods, and make Account an interface. When you do that, you don't have to go through your code renaming the type of every reference to Account When you extract an interface, you don't have to extract all of the public methods on the class you are extracting from. Lean on the Compiler to find the ones that are being used If you want to have access to a non-virtual function through an interface and it isn't on a class with no subclasses, the best thing to do is add a new virtual method with a new name. That method can delegate to a non-virtual or even a static method. You just have to make sure that the method does the right thing for all of the subclasses.
Dependencies on libraries are killing me
Avoid littering direct calls to library classes in your code. You might think that you'll never change them, but that can be come a self-fulfilling prophecy Library designers who use language features on enforce design constraints are often making a mistake. They forget that good code runs in production and test environments. Constraints for the former can make working in the latter nearly impossible (final, sealed keyword make it difficult to fake class/objects under test) Sometimes using a coding convention is just as good as using a restrictive language feature. Think about what your tests need??????????
Pinch Point Traps
Be careful of unit tests slowly grow into mini integration tests. Overtime, we can write narrower unit tests for each of the classes we are touching as we do our work. Eventually, the tests at the pinch point can go away and let the tests for each class support your development work.
Most Important Thing about Software
Behavior is the most important thing about software. It is what users depend on. Users like when we add behavior (provided it is what they really wanted), but if we change or remove behavior they depend on (introduce bugs), they stop trusting us.
Suppose you have a class that is difficult to instantiate in a test harness due to complex dependencies in a single method. Which of the following would be the best approach to get the class to a place where it is testable? Select one: a. Break Out Method Object b. Sprout Class c. Sprout Method d. Extract Implementor
Break Out Method Object
What is the missing step 3 in the Legacy Code Change Algorithm as described in the WELC text? 1. Identify change points 2. Find test points 3. _______________ 4. Write tests 5. Make changes and refactor a. Sense changes b. Create dependencies c. Break dependencies d. Cover and modify
Break dependencies
Dependency Breaking - Break Out Method Object
Break out Method Object has several variations. In the simplest case, the original method doesn't use any instance variables or methods from the original class. We don't need to pass it a reference to the original class In other cases, the method only uses data from the original class. At times, it makes sense to put this data into a new data-holding class and pass it as an argument to the method object. In case, methods from the original class are used. Use Extract Interface and start to build up some abstraction between the method object and the original class.
Varieties of Methods Monster
Bulleted Methods: nearly no indentation Snarled Methods: dominated by single large, indented section. Most methods are not purely bulleted or snarled.
I need to make a change, what methods should I test?
Characterization tests to pin down the behavior that is already there. Reasoning about the effects Reasoning forward Effect propagation Tools for effects reasoning Learning from effect analysis Simplifying effect sketches
My Test code is in the way
Class Naming Conventions Test Location It's important to consider how easy it will be to navigate back and forth between your classes and your tests
Naked CRC
Class, Responsibility and Collaborations. The key is that you are able to use motion and position to how how parts of the system interact. There are 2 guidelines in Naked CRC: 1) Cards represent instances, not classes 2) Overlap cards to show a collection of them
Effect Propagation
Effects propagate in code in 3 basic ways: 1) Return values that are used by a caller 2) Modification of objects passed as parameters that are used later 3) Modification of static or global data that is used later Some languages provide additional mechanisms. For instance, in aspect oriented languages, programmers can write constructs called aspects that affect behavior of code in other areas of the system
Single Responsibility Principle
Every class should have a single responsibility: It should have a single purpose in the system, and there should be only 1 reason to change it.
Characterizing Classes
Figure out what the class does at the high level: 1) Look for tangled pieces of logic. If you don't understand an area of code, consider introducing a sensing variable to characterize it. 2) As you discover the responsibilities of a class, stop to make a list of the things that can go wrong. 3) Think about the inputs you are supplying under test 4) Explore the invariants. Attempt to write tests to verify them. Often you might have to refactor to discover these conditions. Tests to characterize the code are the living documentation of the system's actual behavior.
Dependency Breaking - Supersede Instance Variable
Generally, it is poor practice to provide setters that change the base objects that an object uses. Those setters allow clients to drastically change the behavior of an object during its lifetime. When someone can make those changes, you have to know the history of that object to understand what happens when you call on of its methods. When you don't have setters, code is easier to understand.
Notes/Sketching
Great way of maintaining mental state when we are trying to understand something particularly complex
Scratch Refactoring
Great way to get down to essentials. First risk, we could make some gross mistake that leads us to false view of the system. Second risk, we could get attached to the end point, which could prevent us from the insights on the code
Dependency Breaking - Extract and Override Factory Method
Hard coded initialization work in constructores can be very hard to work around in testing It does have some language specific issues. For example, C++ does not allow virtual function calls to resolve functions in derived classes. Supersede Instance Variable and Extract and Override Gtter and good alternatives
High-level tests vs Unit tests
Higher-level tests can be useful in refactoring. Often people prefer them to finely grained tests at each class because they think that change is harder when lots of little tests are written against an interface that has to change. In fact, changes are often easier than you would expect because you can make changes to the tests and then make changes to the code, moving the structure along in small safe increments. while higher-level tests are an important tool, they shouldn't be substitute for unit tests. Instead, they should be a first step toward getting unit tests in place
How do I know that I'm not breaking anything?
Hyperaware Editing Single Goal Editing Preserve Our Signatures Learn on Compiler
The case of construction blob
I don't like to use Supersede Instance Variable unless I can't avoid it. The potential for resource-management problems is too great. Often I like to use Extract and Override Factory Method, and we can't do that in C++ constructors. For that reason, I use Supersede Instance Variable occasionally.
Dependency Breaking - Encapsulate Global References
If several globals are always used or are modified near each other, they belong in the same class Referencing a member a class rather than a simple global is only the first step. Afterward, consider whether you should use "Introduce Static Setter", or parameterize the code using Parameterize Constrtuctor or Parameterize Method When you use Encapsulate Global References, start with data or small methods. More substantial methods can be moved to new class when more tests are in place To encapsulate references to free functions, make an interface class with fake and production subclasses. Each of the functions in the production code should do nothing more than delegate to a global function.
The case of onion parameter
In any language where we can create interfaces or classes that act like interfaces, we can systematically use them to break dependencies
Learning from effect Analysis
In general, programming gets easier as we narrow effects in a program. We need to know less to understand a piece of code. At the extreme, we end up with functional programming in languages such as Scheme and Haskell. Regardless, in OO languages, restricting effects can make testing much easier, and there aren't any hurdles to doing it.
I need to make change, but I don't know what tests to write
In the natural flow of development, tests that specify become tests that preserve. Characterization Tests Characterizing Classes Targeted Testing A heuristic for writing Characterization Tests
I need to make many changes in 1 area. Do I have to beak dependencies for all the classes involved?
Interception points Judging Design with Pinch Points Pinch Point traps
The case of aliased parameter
Interfaces are great for breaking dependencies, but when we get to the point we have nearly 1-1 relationship between classes and interfaces (or interface for each class in the hierarchy) the design get cluttered. Subclass and Override Method can helps us break dependencies on parameters.
The case of horrible include dependencies
Introduce alternative definitions of methods can separate include files that can be used across set of test files We have to create separate program and we really aren't breaking dependencies at the language level, so we aren't making the code cleaner as we break the dependencies and we have to maintain the duplicated definitions. If the class is going to be broken up into a large number of smaller classes overtime, It can act as a testing point for lots of refactoring. It should not be used often or lightly.
The manual refactoring Challenge for monster methods
Introduce sensing variable: add a variable to a class and use it to sense conditions in the method that we want to refactor. We can get rid of the variables after we're done with the refactoring. Extract what you know: start small and find little pieces of code that we can extract confidently without tests, and then add tests to cover them. Gleaning dependencies: write tests for methods that you need to preserve. Afterward, you extract things that the tests do not cover. Break out a method object
Wrap Method
Introduces seam while adding new features Explicitly makes new functionality independent of existing functionality Could lead to poor names
__________ time is the amount of time that passes between a change that you make and the moment that you get real feedback about the change. Breaking dependencies so we can write and run fast automated tests helps us reduce this.
Lag
Conversation Scrutiny
Listen to conversations about your design. Are the concepts you're using in the conversation the same as the concepts in the code Domain driven design (bounded context)
Object Seams
Most useful seams in available object-oriented programming languages. Change/Mock object's behavior to put the code in test harness
Dependency Breaking - Extract Implementer
Naming is the key part of design. If you choose good names, you reinforce understanding in a system and make it easier to work with. If you choose poor names, you undermine understanding and make life hellish for the programmers who follow you. When you have a class embedded in a hierarchy, you really have to consider whether you are better off using Extract Interface and picking different name for you interfaces. It is a far more direct refactoring.
I don't understand the code well enough to change it
Notes/Sketching Listing Markup Scratch Refactoring Delete Unused Code
Dependency Breaking - Primitivize Parameter
Of it is good predecessor to Spout Class This leaves code in a rather poor state. Overall, it is better to add new code to the original class or to use Sprout Class to build up some new abstractions that can serve as a base for further work. The only time I use Primitivize Parameter is when I feel confident that I will take the time to bring the class under test.
The case of hidden dependencies
Often we can use Extract and Override Getter, Extract and OverrideFactoryMethod and Supersede Instance variable, but I like to use Parameterize Constructor as often as I can.
Judging Design with Pinch Points
Often when I look for pinch points, I start to notice how responsibilities can be reallocated across classes to give better encapsulation Use effect sketches to find hidden classes. The discussions that you have about naming have benefits far beyond the work that you are currently doing. They help you and your team develop a common view of what the system is and what it can become.
Dependency Breaking - Introduce Static Setter
One alternative to decreasing constructor protection and subclassing is to use "Extract Interface" on the singleton class and supply a setter that accepts an object with that interface. The downside of this is that you have to change the type of reference you use to hold the singleton in the class and the type of return value of the instance method. These changes can be quite involved, and they don't really move us to a better state is to reduce global references to the singleton to the point that it can just become a normal class. Parameter missing (common super class). Pass the global to the class upon creation and slowly move away from having globals at all.
What is an interception point and why do we care?
Place in your program where you can detect the effects of a particular change.
What is a pinch point?
Place where tests against a couple of methods can detect changes in many methods.
The case of hidden method
Preferably to test through public method Can the private method be moved to new class? They can be public on that class and our class can create an internal instance of it. That makes the methods testable and the design better. Subverting access protection (through reflection and special permissions) prevents the team from noticing just how bad he code is getting
Single Goal Editting
Programming is the art of doing one thing at a time. When you're programming, it is pretty easy to pick off too big of a chunk at a time. If you do, you end up thrashing and just trying things out to make things work rather than working very deliberately and really knowing what your code does.
Dependency Breaking - Replace Global Reference With Getter
Provide getter for the global reference. Subsequently, it could be overriden in the subclass to put the code in the test harness
Dependency Breaking - Pull Up Feature
Pull methods that we want to test up into an abstract superclass and create a concrete subclass that we can use to test them. Features are spread across multiple classes (can move toward delegation later when more tests are in place)
Dependency Breaking - Text Redefinition
Redefine partial objects' behaviors in the fly. New method replaces the old one until the program ends. This can cause trouble if you forget that a particular method has been redefined by a previous test.
This Class is too big and I don't want it to get any bigger.
Seeing Responsibilities Read books about Design Patterns Help out open source projects Read other people's code. Extract Class (careful of moving methods override another method, one responsibility at a time) Scratch Refactoring
Link Seams
Separate library for any classes or functions you want to replace. Then, alter the build scripts to link to those rather then the production ones when you're testing If you use link seams, make sure that the difference between test and production environments is obvious
Dependency Breaking - Push Down Dependency
Separate the problematic dependencies from the rest of the class, making it easier to work with in a test harness.
Replace Function with Function Pointer
Similar to Link Substitution. However, Link substitution can cause nontrivial build changes. Provide more flexibility compared to Link Substitution (happens completely at compile time, have minimum impact on the build system)
Strategy for monster methods
Skeletonize Methods: when you're done, all that left in the method is a skeleton, control structure and delegations to other methods Find Sequences: extract body and the condition into single method so it's easier to find the sequence of methods I skeletonize methods when I feel that the control structure will need to be refactored after it is clarified, I attempt to find sequences when I feel that identifying an overarching sequence will make the code clearer Extract to current class first: We can always move the method to another class later when the best direction for our changes present itself. In the meantime, extracting to current class moves us forward and it is less error prone. Extract small pieces FIRST Be prepared to redo extractions. Each extractions would give you the insight to the old design and a better way of moving forward
My Application is all API call
Skin and Wrap the API: we make the interfaces that mirror the API as close as possible and then create the wrappers around the library classes. Skin and Wrap the API is good for: 1) the API is relativelysmall 2) You want to completely separate out dependencies on a third-party libray 3) You don't have tests and you can't write them because you can't through the API Responsibility-Based Extraction, we identify responsibilities in the code and start extracting methods for them. Responsibility-Based Extraction is good for: 1) the API is more complicated 2) You have the tool that provides a safe extract method support, or you feel confident that you can do the extractions safely by hand. Thin wrapper for testing and a higher-level wrapper to present a better interface to their application.
I don't have much time to change it
Sprout Method Sprout Class Wrap Method Wrap Class
Which of the following would you use to make code more testable when you are adding new code (as opposed to when you are just testing existing code)? Select one: a. Break Out Method Object b. Sprout Class c. Sprout Method d. Extract Implementor
Sprout Method, Sprout Class
The case of irritating global dependencies
Subclass and Override Method to get fake singleton in place. Extract Interface on the singleton and change all references in the application so that they use the interface name. We can Lean on the Compiler to make the change. Extract Implementer, Introduce Static Setter can be used to get tests in place despite extensive global dependencies. When Parameterize Method and Parameterize Constructor are used, you trade a global reference for either a temporary variable in a method or a field in the object. It can also leads to additional methods/fields and make the conceptual context harder to grasp We should look into making concerted effort to separate responsibilities in an application, this would make dependencies become localized and easier to put the class under test harness.
How Do I add Feature?
TDD Programming by Difference
Hyperaware Editing
TDD foster hyperaware Editing. When you can get your code into a test harness and run tests against it in less than a second, you can run the tests whenever you need to incredibly fast and really know what the effects of a change made. Pair programming also helps.
Refactoring
The act of improving design without changing its behavior. We can use this to make software more maintainable without changing behavior. Use tests to verify to the process.
I can't run this method in a test harness
The case of hidden method The case of helpful language feature The case of the undetectable side effect
I can't get this class into a test harness?
The case of the irritating Parameter The case of hidden dependency The case of construction blob The case of irritating Global Dependencies The case of horrible include dependencies The case of onion parameter The case of aliased parameter
Reasoning about effects
The key is to have a separate bubble for each variable that can be effected and each method whose return value can change. If you code is well structured, most of the methods in your software have simple effect structures. If we make a particular change, how could it possibly affect the rest of the results of the program
coupling count
The number of values that pass in and out of a method when it is called. If there is no return value, it is the number of parameters. If there is, it is the number of parameters plus one. Coupling count can be a very useful thing to compute for small methods you'd like to extract if you have to extract without tests.
Dependency Breaking - Link Substitution
To replace one function with another (at build time)
My Application has no structure
Traditionally, many organizations have used the role of architect to preserve the big picture for the team. The key way to keep an architecture intact is to make sure that everyone on the team knows what it is and has a stake in it. Telling story of the system Naked CRC Conversation Scrutiny
(T/F) Changing the scope of a private member variable in a class can change the corresponding effect sketch.
True
Which of the following is not a proposed seam type in the WELC text? a. Object b. Unit Test c. Link d. Preprocessor
Unit Test
Dependency Breaking - Adapt Parameter
Use Adapt Parameter when you can't use Extract Interface on a parameter's class or when a parameter is difficult to fake Move toward interfaces that communicate responsibility rather than implementation details. This makes code easier to read and easier to maintain Adapt Parameter is one case in which we don't "Preserve Signatures" Use extra care
Programming by Difference
Use inheritance to introduce behaviors without modifying a class directly Overuse inheritance can cause the design to degrade rapidly. We can use tests to move to a cleaner design
Dependency Breaking - Extract and Override Call
Useful technique to break dependencies on global variables and static methods. If there are many differnet calls against the same global, use Replace Global Reference with Getter.
I need to change a monster method and I can't write tests for it
Varieties of Monsters method Tackling Monsters with Automated Refactoring support for Java The Manual Refactoring Challenge Strategy
Telling story of the system
What are the most important things to communicate? To really convey the system architecture that briefly, you have to simplify If you have to choose between 2 ways of doing something, the story can be a good way to see which one will lead to an easier to understand system
Interface Segregation Principle
When a class is large, rarely do all of its clients use all of its method. Often we can see different groupings of methods that particular clients use. If we create for each of these mappings and have the large class implement those interfaces. each client can see the big classes through that particular interface. The clients no longer have to recompile whenever the large class does.
Tackling Monsters Method with Automated Refactoring Support
When doing automated refactoring without tests, use the tool exclusively. After a series of automated refactorings, you can often get tests in place that you can use to verify manual edits that you make. When you do your extraction, these should be your key goals 1) To separate logic from awkward dependencies 2) To introduce seams that make it easier to get tests in place for more refactoring
The case of helpful language feature
When we depend directly on libraries that are out of our control, we are just asking for trouble Adapt Parameter/Lean on Compiler to break direct dependencies on the library classes that are hard to put under test harness.
Simplifying Effect Sketches
When we remove tiny pieces of duplication, we often end up getting effect sketches with a smaller set of endpoints. In well encapsulated code, there are fewer paths to follow as you try to understand it. Breaking encapsulation can make reasoning about our code harder, but it can make it easier if we end up with good explanatory tests afterward. When we have test cases for a class, we can use them to reason about our code more directly. We can also write new tests for any questions that we might have about the behavior of the code.
Dependency Breaking - Expose Static Method
When you are breaking dependencies without tests "Preserve Signatures" of methods whenever possible. If you cut/copy and paste whole method signatures, you have less of a chance of introducing errors. Static methods and data really do act as if they are part of a different class. Static data lives for the life of a program, not the life of an instance, and statics are accessible without an instance. The static portions of a class can be seen as a "staging area" for things that don't quite belong to the class. If you see a method that doesn't use any instance data, it is a good idea to make it static to make it noticeable until you figure out what class it really belongs on.
Reasoning Forward
When you are sketching effects, make sure that you have found all of the clients of the class you're examining. If your class has a superclass or subclasses, there might be other clients that you haven't considered.
Dependency Breaking - Extract and Override Getter
When you use Extract and Override Getter, you have to be very conscious of object lifetime issues, particularly in a non-garbage collected language such as C++. Make sure that you delete the testing instance in a way that is consistent with how the code deletes the production instance. There is a chance that someone will use the variable before it is initialized. For this reason, it's good to make sure all of the code in the class is using the getter
Targeted Testing
When you write a test for a branch, ask yourself whether there is any other way that the test could pass, aside from executing that branch. If you're not sure, use a sensing variable or the debugger to find out whether the test is hitting it. When we refactor, we generally have to check for 2 things: Does the behavior exist after the refactoring and is it connected correctly? Many characterization tests look like "sunny days" tests. They don't test many special conditions; they just verify that particular behaviors are present. From their presense, we can infer that refactorings that we have done to move or extract code have preserved behavior. The most valuable characterization tests exercise a specific path and exercise each conversion along the path.
mock object
a fake object that asserts conditions internally.
test harness
a piece of software that enables unit testing.
change point
a place in code where you need to make a change.
interception point
a place where a test can be written to sense some condition in a piece of software.
Which technique is particularly useful when trying to understand a very long method? Select one: a. Listing Markup b. Notes/Sketching c. Random Refactoring d. Delete Unused Code
a. Listing Markup
Feature sketches, grouping methods, and looking for internal relationships are all heuristics used to break down overly big classes. What is the principle that guides all of this work? Select one: a. Single Responsibility Principle b. Interface Segregation Principle c. Multiple Primary Responsibility Principle d. Elementary School Principal
a. Single Responsibility Principle
Which of the following is NOT a way that effects propagate in code? Select one: a. modifications of primitive pass-by-value parameters b. modification of static or global data that is used later c. modification of objects passed as parameters that are used later d. return values that are used by a caller
a. modifications of primitive pass-by-value parameters
The Liskov Substitution Principle states that ___________. Select one: a. objects of subclasses should be substitutable for objects of their superclasses throughout the code b. irritating parameters should be substituted by objects that implement interfaces c. substitute teachers should never become principals d. languages that have a common object parent are inherently better than languages that don't
a. objects of subclasses should be substitutable for objects of their superclasses throughout the code
A _________ method is a method dominated by a single large, indented section. Select one: a. snarled b. bulleted c. sensing d. gleaning
a. snarled
Gleaning dependencies involves ___________. Select one: a. writing tests for the main logic of a method, then extracting things not covered by the tests b. extracting the main logic of a method, so what remains can be covered with tests c. picking out the bad dependencies and removing them from the code altogether d. depending on scraps to survive
a. writing tests for the main logic of a method, then extracting things not covered by the tests
fake object
an object that impersonates a collaborator of a class during testing.
In the situation where you have parameter dependencies that make it difficult to test a method, one option is to use Extract Interface. If Extract Interface is too difficult (e.g. too many methods in interface), what other dependency breaking technique can you use? Select one: a. Expose Static Method b. Adapt Parameter c. Extract and Override Factory Method d. Break Out Method Object
b. Adapt Parameter
Suppose you have a constructor that contains some complex code in the constructor like this: public class Example { private NeededClass field1; public Example() { NastyClass1 nc1 = new NastyClass1(AppConfig.getConfig()); NastyClass2 nc2 = new NastyClass2(nc1); this.field1 = new NeededClass(nc1, nc2); } } What could you do to get Example under test without having to instantiate NastyClass1 and NastyClass2? Select one: a. Make the Example() constructor static b. Extract the creation of NeededClass into a Factory Method, and override the Factory Method to return a fake NeededClass c. Write a Factory Method that creates an instance of Example, and override the Factory Method to return a fake Example d. Make the Example() constructor private
b. Extract the creation of NeededClass into a Factory Method, and override the Factory Method to return a fake NeededClass
When you are faced with code that has a lot of dependencies to a relatively small API, and it is difficult to test, which technique informs you to make interfaces that mirror the API closely, and create new classes around library classes? Select one: a. Push-Down Dependency b. Skin and Wrap API c. Responsibility-Based Extraction d. Mirror and Make More
b. Skin and Wrap API
Parameterize Constructor is essentially the same thing as _________. Select one: a. setter injection (dependency injection where you pass in the dependency through a setter) b. constructor injection (dependency injection where you pass in the dependency through the constructor) c. polymorphism in non-object-oriented languages d. lethal injection (dependency injection where you pass in a deadly dependency)
b. constructor injection (dependency injection where you pass in the dependency through the constructor)
When using the Naked CRC approach, what do blank cards represent? a. classes b. instances of classes c. methods d. interfaces e. components
b. instances of classes
Bertrand Meyer's Open/Closed Principle recommends that code should be open for _______ and closed to ___________. Select one: a. open for inspection, closed to testing b. open for extension, closed to modification c. open for suggestions, closed to criticism d. open for modification, closed to extension
b. open for extension, closed to modification
When faced with an irritating parameter that makes testing difficult, one of the first simple steps recommended by Feathers is to __________. Select one: a. give up and cry b. pass null c. write a new method that excludes the parameter d. create a subclass for the parameter's type and pass an instance of it
b. pass null
What kind of release is typically only distributed to users internal to an organization? a. Final b. Beta c. Alpha d. Gamma
c. Alpha
The case of irritating Parameter
cause trouble in creating the class in test harness When you are writing tests and an object requires a parameter that is hard to construct, consider passing null instead. However, don't pass null in production code. Consider using Null Object Pattern instead. Null objects are useful specifically when a client doesn't have to care whether an operation is successful. Extract Interface from parameter object and Subclass and Override Method are possible solution
A _____________ test is used to determine the actual behavior of existing code. a. automated b. unit c. characterization d. integration
characterization
Characterization Tests
characterizes the actual behavior of a piece of code. Characterization tests record the actual behavior of a piece of code. If we find something unexpected when we write them, it pays to get some clarification. It could be a bug. That doesn't mean that we don't include the test in our test suite, we should mark it as suspicious and find out what the effect would be fixing it. Before you use a method in a legacy system, check to see if there are tests for it. If there aren't, write them. When you do this consistently, you use tests as a medium of communication. People can look at them and get a sense of what they can and cannot expect from the method. The act of making a class testable in itself tends to increase code quality. People can find out what works and how; they can change it, correct bugs and move forward.
Problems with big classes? How can we work without making things worse?
confusion, it's often hard to get a sense of what you have to change and whether it is going to affect anything else. It's hard to test. Either the changes take far too long or the bug count increases. Sprout Methods and Sprout Classes can keep things from getting much worse. Note that the names of the methods often give you hints about how to break down a class into smaller pieces.
Dependency Breaking - Parameterize Constructor
create the object outside the class, and make clients pass the constructor as a parameter. Explicitly depend on new types that were used in the class before but were not present at the interface (Consider Extract and Override Factory Method to remove dependency)
According to JUnit best practices, where should JUnit tests be placed? Select one: a. In the same folder alongside the src code, but with class names that start with Test so they are separate from the src code b. In a package that ends with the name test c. Tests should be embedded in the source code files d. In a test folder with the same package name as the src folder
d. In a test folder with the same package name as the src folder
Which pattern involves making a current class abstract, and placing problematic code in a subclass so the methods in the abstract class can be tested. Select one: a. pull up b. extract method c. abstractify d. push down
d. push down
Which of the following is NOT a recommendation in the WELC text for getting procedural code under test in order to add code? Select one: a. bias toward introducing new functions rather than adding code to old ones b. use a link seam to remove unwanted code when testing c. use the macro preprocessor to remove unwanted code when testing d. use comments to remove unwanted code when testing
d. use comments to remove unwanted code when testing
What does it mean to lean on the compiler?
even before I have a chance to run what tests I do have, compile-time checking provided confidence to make changes quickly.
The Dependency Inversion Principle pushes you to depend on _________ because they change less often. Select one: a. parameters b. inner classes c. interfaces d. local objects
interfaces
According to Martin Fowler, refactoring is a change made to the __________ of software to make it easier to understand and cheaper to modify without changing its existing behavior. Select one: a. reputation b. internal structure c. automated tests d. documentation
internal structure
Given the release numbering scheme discussed in class (x.y.z[[A|B] w]), match each letter with the proposed meaning. iteration of the alpha or beta release defect repair number feature release number major release number
iteration of the alpha or beta release → w defect repair number → z feature release number → y major release number → x
Lean on compiler
let compiler guide you toward the changes you need to make involves 2 steps: 1) Altering a declaration to cause compile errors 2) Navigating to those errors and making changes Before with lean on compiler when using inheritance. Might not be practical if the build is long
My project is not object oriented. How do I make safe changes?
looks for pinch point, use link seam and pre-processing seam (language with macro pre-processor) We can write tests for the new function that we write (TDD) When procedural languages have object-oriented extensions, move toward OO (if you language allow). Object seams are much more preferable compared to link and preprocessing seams
Preprocessing Seams
macro preprocessor runs before the compiler It tends to decrease code clarity and force you to maintain several different programs in the same source code.
Which of the following is not likely part of the role of the system integrator? Select one: a. manages branches/tags b. manages build environment c. manages acceptance testing/functional verification d. manages software review/inspection process
manages software review/inspection process
Dependency Breaking - Definition Completion
obligated to create separate executable for the tests that use the completed definitions. (otherwise, will clash with real definitions at link time) we now have 2 different sets of definitions for the methods of a class. This could leas to big maintenance burden. Using it to break initial dependencies. Afterwards, you should bring the class under test quickly so that duplicate definitions can be removed.
The Capture-Mark-Recapture testing approach uses two independent teams to do what? Select one: a. play a game of capture the flag with testers b. demonstrate the quality of an internal test team c. predict how many undiscovered defects still exist d. determine if defect fixes have introduced regression defects
predict how many undiscovered defects still exist
Dependency Breaking - Template Redefinition
provide alternate definitions of methods rather than data to put the class in test harness. Code that was in implementation files moves to headers when you templatize it. This can increase the dependencies in systems. Users of the template then are forced to recompile whenever the template code is changed.
Tools for effect Reasoning
scope variable const keyword encapsulation
According to the WELC author, faking collaborators (or using Mock Objects) is primarily a way to accomplish which of the following? Select one: a. separation b. sensing
sensing
I'm changing the same code All Over the place
start small. If I can remove tiny pieces of duplication, I do those first because often it makes the big picture clearer When 2 methods look roughly the same, extract the differences to other methods. When you do that, you can often make them exactly the same and get rid of one. When we have good design, we just don't have to change code much to add new features
Suppose you want to test a method in a Java class that is difficult to instantiate in a test harness, but the method does not use any instance data or instance methods. One option is to turn it into a ________ method.
static
Dependency Breaking - Subclass and Override Method
use inheritance in the context of a test to nullify behavior that you don't care about or get access to behavior that you do care about.
Listing Markup
useful for long methods use marker to group things to separate responsibilities line up blocks (draw lines from beginnings of blocks to the ends) ???? not seen much in practice
Preserve Signatures
when avoid changing signatures at all, you can cut/copy and paste entire method signatures from place and minimize any chances of errors.
Place the steps of TDD in the proper order (1 being first). get code and test to compile repeat make test pass write a failing test case remove duplication
write a failing test case → 1, get code and test to compile → 2, make test pass → 3, remove duplication → 4, repeat → 5,
Dependency Breaking - Parameterize Method
you want replace the object created internally by the methods to sense or separate. One way to do it is to pass the object from the outside. Explicitly depend on new types that were used in the class before but were not present at the interface (Consider Extract and Override Factory Method to remove dependency)