{Refractoring - Improving the design of existing code} - 1999

Forword:

Design patterns are targets for refactoring, but transforming your code so that you get there is another challenge.

One step at a time.


Perface:

What is refactoring?

It's a process of changing a software in such a way that it doesn't alter the external behavior of the code yet improves its internal structure.

It's a disciplined way to clean up code that minimizes the chances of introducing bugs.

OCP --- open closed princple


How to read this book:

Chap 1.

Takes a small example and show the process of refractoring.

Chap 2.

Cover more of the general principles of refractoring.

Chap 3.

Describe how to find bad codes and how to do refactorings. Tests are very important.

Chap 4.

Describe how to build tests into code with a simple open-source Java testing framework.

Chap 5 - 14.

Skip read them and if you want to do refactoring, then read them carefully.

Chap 15.

The art of refactoring.



Chap 1. REFACTORING, A FIRST EXAMPLE

When you find you have to add feature to a program, and the program's code is not structured in a convenient way to add the feature, first refactor the program tomake it easy to add the feature and then add the feature.


Before you start refactoring, check that you have a solid suite of tests. These tests must be self-checking.


Refactoring changes the programs in small steps. If you make a mistake, it is easy to find the bug.


Any fool can write code that a computer can understand. Good programmers write code that humans can understand.


Test, small changes, test and so on .. It is that rhythm that allows refactoring to move quickly and safely.



Chap 2. PRINCIPLES IN REFRACTORING

Definition:

Refactoring: a change made to the internal structure of software to make it easier to understand and cheaper to modifywithout changing its observable behavior.

To reconstructure software by applying a series of refractoring without changing its observable behavior.


Two hats:

We are swapping 2 hats, adding functions and refactoring

When adding a function, we just add new capabilities, and measure our progress by adding new tests, we shouldn't change existing code.

When refactoring, we only change structure and don't add functions or add tests.


Why should we refactor?

Improves the design of software.

Loss of the structure of code has a cumulative effect. Regular refactoring helps code retain its shape.

By reducing duplications, we ensure that the code says everything once and only once, which is the essence of good design.


Makes software easier to understand.

The code says its intention. And refractoring helps us understand other's code.


Helps you find bugs.

By clarifying the structure of the program, we can know more about how it works. 

I'm not a great programmer, I'm just a good programmer with great habits.


Helps you program faster.

A good design is essential to maintaining speed in software development. Refractoringstops the design of the system from decaying. It can improve our design.



When should we refactor?

Refactoring is something you do all the time in little bursts, you refactor because you want to do sth else, and it helps you do that other thing.


The rule of three:

Refactor when you add function:

Refactor helps us understand the code we need to modify. Refactoring is a quick and smooth process which improves our design.

Refactor when you need to fix a bug.

If you get a bug report, it's a sign you need refactoring, because the code wasnot clear enough for you to see there was a bug.

Refactor as you do a code review.

Refactoring helps the code review have more concrete results. Better to have 1 reviewer and 1 original author.

Larger reviews use UML diagrams. Extreme Programming and Pair Programming.


Why Refactoring Works: 

We want programs work not today but also for tomorrow. 

We want programs that are easy to read, that have all logic specified in one and only one place, that do not allow changes to endanger existing behavior, and that allow conditional logic to be expressed as simply as possible.

Computer Science is the discipline that believes all problems can be solved with one more layer of indirection.

To enable sharing of logic --- reduce duplication.

To explain intention and implementation separately.

To isolate change.

To encode conditional logic --- Polymorphism


Problems with Refactoring:

Databases:

Difficult to change: 

1. business applications are tightly coupled to the database schema that supports them. 

2. changing the database schema forces you to migrate the data.

Nonobject databases: place separate layers and update intermediate layer.

Object databases: some provide auto migration but still tricky.


Changing interfaces:

If you change a public interface, you have to retain both the old and new interfaces. After our users react, we then delete old one.

See collections as an example.

Don't publish an interface unless you really need to.

Add a super exception to interfaces.


Design changes that are difficult to refactor:

We pick the simplest way to refactor.


When shouldn't you refactor?

When you need to rewrite is when the current code just does not work.

Code has to work mostly correctly before you refactor.

When you are close to a deadline, avoid refactoring. 

Not having enough time usually is a sign that you need to do some refactoring.


Refactoring and Design

Combine refactoring and upfront design:

We make design simpler. If we find refactor a simple solution to the flexible solution, we just implement the simple one.

Even if you know exactly what is going on in your system, measure performance, don't speculate. You will learn something and nine times out of ten, it won't be that you were right.

Refactoring and Performance

Write tunnable software first and then to tune it for sufficient speed.

Approaches to write fast software:
1. time budgeting, used often in hard real-time systems such as heart peacemakers.
2. constant attention approach, but doesn't work very well. Because we can't guarantee the faster result.
3. You build your program in a well-factored manner without paying attention to performance until you begin a performance optimization stage. 
3.1 Running the program under a profiler that monitors the program and tells you where it is consuming time and space.
  3.2 Focus on the performance hot spots and refactor them and see whether performance improved. --- McConnel method

Refactoring gives us time to spend on performance tuning and finer granularity for your performance analysis.



Chap 3 BAD SMELLS IN CODE

Duplicated Code: extract same parts
Long Method: The object programs that live best and longest are those with short methods.  Extract methods with good names related to comments.
Large Class
Long Parameter List
Divergent Change: classes are changed into different ways for different reasons.
Shotgun Surgery: every time you make a change, you have to make a lot of little changes to a lot of different classes.
Feature Envy
Data Clumps: Bunches of data that hang around together really ought to be made into their own objects. Reducing field lists and parameter lists will certainly move a few bad smells.
Primitive Obsession
Switch statements: consider polymorphism
Parallel Inheriance Hierarchies: every time you make a subclass of one class, you also have to make a subclass of another.
Lazy Class: a class that isn't doing enough to pay for itself should be eliminated.
Speculative Generality: the only users of a method or class are test cases. 
Temporary Field: a field is only used in certain methods may be confusing.
Message Chains: you see a long line of methods or a sequence of temps.
Middle Man: a class's interface's most methods are delegating to other class.
Inappropriate Intimacy: inheriance often can lead to overintimacy.
Alternative Classes With Different Interfaces: methods do the same thing but have different signatures.
Incomplete Library Class: we don't know whetherr library is complete or omniscient.
Data Class: just contain fields, need responsiblities
Refused Bequest: subclass don't want superclass's methods or fields. Just replace inheriance with delegation.
Comments: not too much comments.

When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.
A good time to use a comment is when you don't know what to do and say why you did something.

Chap 4 BUILDING TESTS

The value of self-testing code:

Make sure all tests are fully automatic and that they check their own results.
A suite of tests is a powerful bug detector that decapitates the time it takes to find bugs.
One of the most useful times to write tests is before you start programming. By writing tests you concentrate on the interface and what the function should do.


The JUnit Testing Framework:

Run your tests frequently. Localize tests whenever you compile every test at least every day.
When writing tests, start by making them fail. With it we can prove that that's actually testing.

Unit and functional tests:

Unit tests: highly localized, used to expose the bug.
Functional tests: ensure the whole software works, treat the whole system as a black box and should be done by another team.

Adding more tests:

Test areas that you are most worried about going worry.
Think of the boundary conditions under which things might go wrong and concentrate your tests there.
Don't forget to test that exceptions are raised when things are expected to go wrong.
Look at the code and concentrate on where the risk is and where it becomes complex and consider the likely areas of error.
Don't let the fear that testing can not catch all bugs stop you from writing the tests that will catch most bugs.
When we have composition of subclasses, it's better to test independently. We can copy code.



Chap 5 TOWARD A CATALOG OF REFACTORINGS

Format of the refactorings:
1. name: with a short summary of the situation in which you need the refactoring and a summary of what the refactoring does.
2. motivation: describes why the refactoring should be done and describes circumstances in which it shouldn't be done.
3. mechanics: a concise and step-by-step description of how to carry out the refactoring.
4. examples: a very simple use of the refactoring to illustrate how it works.

As you use more refactorings, I hope you will start developing your own. 
I hope examples will motivate you and give you a starting point as to how to do that. 


Chap 6 Composing Methods

Composing methods to package code properly.
Extract method: takes a clump of code and turns it into its own method.
You have a code fragment that can be grouped together.
Turn the fragment into a method whose name explains the purpose of the method.

Inline method: take a method call and replace it with the body of the code.
A method's body is just as clear as its name.
Put the body into the body of its callers and remove the method.
When you have a group of methods that seem badly refactored, you can inline them before using Replace Method with Method Object.

Inline temp
You have a temp that is assigned to once with a simple expression and the temp is getting in the way of other refactorings.
Replace all references to that temp with the expression.
The only time it's used is when you find a temp that is assigned the value of a method call.

Replace temp with query: get rid of temporary variables
You are using a temporary variable to hold the result of an expression.
Extract the expression into a method. Replace all references to the temp with the expression. The new method can then be used in other methods.
It's often used before Extract Method, and temps are temporary and local, which tend to encourage longer methods.


Introduce explaining variable
You have a complicated expression.
Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose.
It's useful with conditional logic and can explain each step in a long algorithm.

Split temporary variable: make the temp easier to replace.
You have a temporary variable assigned to more than once, but is not a loop variable nor a collecting temporary variable.
Make a separate temporary variable for each assignment.
Any variable with more than one responsibility should be replaced with a temp for each responsibility.


Remove assignments to parameters
The code assigns to a parameter.
Use a temporary variable instead.

Replace method with method object: break up even the most tangled method, at the cost of introducing a new class.
You have a long method that uses local variables in such a way that you cannot apply Extract Method.
Turn the method into its own object so that all the local variables become fields on that object. You can then decompose the method into other methods on the same object.

Substitute algorithm: introduce the clearer algorithm.
You want to replace an algorithm with one that is clearer.
Replace the body of the method with the new algorithm.


Chap 7 Moving features between objects

Move method
A method is or will be using or used by more features or another class than the class on which it is defined.
Create a new method with a similar body in the class it uses most. Either turn the old method into a simple delegation or remove it altogether.

Move field: better than move method
A field is or will be used by another class more than the class on which it is defined.
Create a new field in the target class, and change all its users.


Extract class: seperate some of these responsibilities
You have one class doing work that should be done by two.
Create a new class and move the relevant fields and methods from the old class into the new class.


Inline class: merge one class into another
A class isn't doing very much.
Move all its features into another class and delete it.

Hide delegate: 
A client is calling a delegate class of an object.
Create methods on the server to hide the delegate.

Remove middle man
A class is doing too much simple delegation.
Get the client to call the delegate directly.


Introduce foreign method: only one or two methods, move responsibilities to this unchangeable class
A server class you are using needs an additional method, but you can't modify the class.
Create a method in the client class with an instance of the server class as its first argument.

Introduce local extension: more than two methods.
A server class you are using needs several additional methods, but you can't modify the class.
Create a new class that contains these extra methods. Make this extension class a subclass or a wrapper of the original.
Subclass VS Wrapper (many problems about overriding)

Chap 8  Organizing Data

Self encapsulate field: generally just use direct access to fields because it's easy to add accessors.
You are accessing a field directly, but the coupling to the field is becoming awkward.
Create getting and setting methods for the field and use only those to access the field.


Replace data value with object: turn dumb data into articulate objects
You have a data item that needs additional data or behavior.
Turn the data item into an object.


Change value to reference: when objects are instances that will be needed in many parts of the program.
You have a class with many equal instances that you want to replace with a single object.
Turn the object into a reference object.


Change reference to value: 
You have a reference object that is small, immutable and awkward to manage.
Turn it into a value object.


Replace array with object: when you see an array acting as a data structure.
You have an array in which certain elements mean different things.
Replace the array with an object that has a field of each element,

Duplicate observed data: GUI classes are doing business logic that they shouldn't. To move the behavior into proper domain classes.
You have domain data available only in a GUI control, and domain methods need access.
Copy the data to a domain object. Set up an observer to synchronize the two pieces of data.


Change unidirectional association to bidirectional: support new functions
You have two classes that need to use each other's features, but there is only a one-way link.
Add back pointers, and change modifiers to update both sets.


Change bidirectional association to unidirectional: removes unnecessary complexity
You have two-way association but one class no longer needs features from the other.
Drop the unneeded end of the association.


Replace magic number with symbolic constant: get rid of magic numbers 
You have a literal number with a particular meaning.
Create a constructor, name it after the meaning, and replace the number with it.

Encapsulate field
There is a public field,
Make it private and provide accessors.

Encapsulate collection
A method returns a collection.
Make it return a read-only view and provide add/remove methods.

Relace record with data class
You need to interface with a record structure in a traditional programming environment.
Make a dumb data object for the record.


Replace type code with class
A class has a numeric type code that does not affect its behavior.
Replace the number with a new class.


Replace type code with subclass
You have an immutable type code that affects the behaviour of a class.
Replace the type code with subclass.

Replace type code with state/strategy
You have a type code that affects the behavior of a class, but you cannot use subclassing.
Replace the type code with a state object.
If you are trying to simplify a single algorithm with Replace Conditional with Polymorphism, strategy is better. If you are going to move state-specific data and you think of the object as changing state, use the state pattern.


Replace subclass with fields
You have subclasses that vary only in methods that return constant data.
Change the methods to superclass fields and eliminate the subclasses.

Chap 9 Simplifying conditional expressions

Decompose conditional: core refactoring, which entails breaking a conditional into pieces and separates the switching logic from the details of what happens.
You have a complicated conditional (if-then-else) statement. 
Extract methods from the condition, then part, and else parts.

Consolidate conditional expression: when you have several tests and all have the same effect.
You have a sequence of conditional tests with the same result.
Combine them into a single conditional expression and extract it.

Consolidate duplicate conditional fragments: remove any duplication within the conditional code.
The same fragment of code is in all branches of a conditional expression.
Move it outside of the expression.

Remove control flag: get rid of the awkward control flags.
You have a variable that is acting as a control flag for a series of boolean expressions.
Use a break or return instead.

Replace nested conditional with guard clauses: clarify special case conditionals.
A method has conditional behaviour that does not make clear the normal path of execution.
Use guard clauses for all the special cases.

Replace conditional with polymorphism: Object-oriented programs rarely have switch statements
You have a conditional that chooses different behavior depending on the type of an object.
Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.
 

Introduce null object: remove checks for a null value.
You have repeated checks for a null value.
Replace the null value with a null object.

Polymorphism: Instead of asking an object what type it is and then invoking some behavior based on the answer, you just invoke the behavior.
Null objects are always constants, and implemented by Singleton pattern.

Introduce assertion: 
A section of code assumes sth about the state of the program.
Make the assumption explicit with an assertion.

Assertions are removed for production code. They act as communication and debugging aids.
Use assertions only to check things that need to be true. 
Always ask whether the code will still works if an assertion fails. If the code does work, remove the assertion.

Chap 10 Making method calls simpler

Rename method
The name of a method does not reveal its purpose.
Change the name of the method.

Add parameter
A method needs more information from its caller.
Add a parameter for an object that can pass on this information.

Remove parameter
A parameter is no longer used by the method body.
Remove it.


Separate query from modifier: most valuable conventions which separate methods that change state from those that query state.
You have a method that returns a value but also changes the state of an object.
Create 2 methods, one for the query and one for the modification.


Parameterize method: combine several similar methods by adding a parameter.
Several methods do similar things but with different values contained in the method body.
Create one method that uses a parameter for the different values.


Replace parameter with explicit methods: have parameters that are used to determine conditional behavior.
You have a method that runs different code depending on the values of an enumerated parameter.
Create a separate method for each value of the parameter.



Preserve whole object:  passing several values from an object
You are getting several values from an object and passing these values as parameters in a method call.
Send the whole object instead.

Replace parameter with method: if you can get the data from an object to which the method already has access, you can eliminate parameters.
An object invokes a method, then passes the result as a parameter for a method. The receiver can also invoke this method.
Remove the parameter and let the receiver invoke the method.


Introduce parameter object
You have a group of parameters that naturally go together.
Replace them with an object.

Remove setting method
A field should be set at creation time and never be used.
Remove any setting method for that field.

Hide method
A method is not used by any other class.
Make the method private.

Replace constructor with factory method
You want to do more than simple construction when you create an object.
Replace the constructor with a factory method.

Encapsulate downcast
A method returns an object that needs to be downcasted by its callers.
Move the downcast to within the method.


Replace error code with exception
A method returns a special code to indicate an error.
Throw an exception instead.

Replace exception with test
You are throwing a checked exception on a condition the caller could have checked first.
Change the caller to make the test first.


Chap 11 Dealing with Generalization

Pull up field
Pull up method
Pull up constructor body
Push down method
Push down field
Extract subclass
Extract superclass
Extract interface
Collapse hierarchy
Form template method
Replace inheritance with delegation
Replace delegation with inheriance

Chap 12 Big Refactoring

Tease apart inheriance: deals with a tangled inheritance hierarchy that seems to combine several variations in a confusing way.

Convert procedual design to objects: sovle the classic problem of what to do with procedural code.

Separate domain from presentation: isolate business logic from user interface code.

Extract hierarchy: simplifies an overly-complex class by turning it into a group of subclasses.

.....



Chap 13 Refactoring, Reuse and Reality

It's our responsibility to work hard to develop and communicate our ideas.
Why you not refactor your programs?
1. You might not understand how to refactor.
2. If the benefits are long-term, why exert the effort now? In the long term, you might not be with the project to reap the benefits.
3. Refactoring code is an overhead activity; you're paid to write new features.
4. Refactoring might break the existing program.

Understanding how and where to refactor.
Refactoring to achieve near-term benefits
Reducing the overhead of refactoring
Refactoring safely

Chap 14 Refactoring Tools


Chap 15 Putting It All Together

When will you really get refactoring?
When you start to calm down and feel absolute confidence that no matter how screwed up someone left it, you can fix it.
If the code is already better, integrate and release what you have done.

How do we learn to refactor?

1. Get used to picking a goal.  get rid of bad smell
2. Stop when you are unsure.
3. Backtrack.    running tests all the time.
4. Duets: work with partners, focus on the trouble by talking and make code more understandable.

Before adding new features, clean it up first.
When you're refactoring, your goal is to leave the code computing exactly the same answers it was when you found it. 
Keep a list of things to change later --- test cases to add or change, unrelated refactorings, documents to write, diagrams to draw.
That way you won't lose your thoughts, but you won't let them mess up what you are doing now.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Your class library works, but could it be better? Refactoring: Improving the Design of Existing Code shows how refactoring can make object-oriented code simpler and easier to maintain. Today refactoring requires considerable design know-how, but once tools become available, all programmers should be able to improve their code using refactoring techniques. Besides an introduction to refactoring, this handbook provides a catalog of dozens of tips for improving code. The best thing about Refactoring is its remarkably clear presentation, along with excellent nuts-and-bolts advice, from object expert Martin Fowler. The author is also an authority on software patterns and UML, and this experience helps make this a better book, one that should be immediately accessible to any intermediate or advanced object-oriented developer. (Just like patterns, each refactoring tip is presented with a simple name, a "motivation," and examples using Java and UML.) Early chapters stress the importance of testing in successful refactoring. (When you improve code, you have to test to verify that it still works.) After the discussion on how to detect the "smell" of bad code, readers get to the heart of the book, its catalog of over 70 "refactorings"--tips for better and simpler class design. Each tip is illustrated with "before" and "after" code, along with an explanation. Later chapters provide a quick look at refactoring research. Like software patterns, refactoring may be an idea whose time has come. This groundbreaking title will surely help bring refactoring to the programming mainstream. With its clear advice on a hot new topic, Refactoring is sure to be essential reading for anyone who writes or maintains object-oriented software. --Richard Dragan Topics Covered: Refactoring, improving software code, redesign, design tips, patterns, unit testing, refactoring research, and tools.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anyanyamy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值