290 likes | 324 Views
Explore the intersection of software engineering and psychology with Jamie Hohman in EECS 816. Learn about refactoring, identifying and resolving "smelly" code, testing, tools, and when to refactor. Discover the power of Blink and its application in coding practices. Gain insights on refactoring techniques to improve code quality and maintainability, while understanding the risks involved. Master the art of refactoring and avoid common pitfalls to enhance software development practices.
E N D
“Blink-factoring”: Software engineering meets pop psychology Presented by Jamie Hohman EECS 816: Object-Oriented Software Development April 22, 2008
Contents • Defining Refactoring • Defining Blink • Identifying types of “smelly” code • Learning refactoring solutions for this code • Deciding when and when not to refactor • Understanding the role of testing • Learning about tools available for refactoring • Breaking down examples throughout
What is Refactoring? • Is either a noun (the actual code changes) or a verb (the act of applying the changes) • Represents a structured and tested method of reversing software decay • Makes no observable changes in functionality • Helps future developers find bugs and add new functionality faster • Ensures code says things once and only once
Why are developers wary? • Don’t know how or when • Automated tools can detect “fishy” areas • No short term benefits • Refactoring results in bugs found in common code, fixed once, and results in smaller code • Constitutes overhead • Pays for itself in more maintainable code • Risk of newly introduced errors • Good practices help eliminate these • Automated tools help reduce the manual, error-prone tasks • Needs to reach The Tipping Point in an organization to be fully accepted
void funcA() { … x = sqr(y); … } void funcB() { … x = sqr(y); … } int sqr(int x) { return x * x; } Duplicate Code What smells in here? void funcA() { int x, y = 2; x = y * y; printf(“%d”, x); } void funcB() { int x, y = 4; x = y * y; funcC(x); } Extract Method
Contents • Defining Refactoring • Defining Blink • Identifying types of “smelly” code • Learning refactoring solutions for this code • Deciding when and when not to refactor • Understanding the role of testing • Learning about tools available for refactoring • Breaking down examples throughout
What is Blink? • Pop psychology book by Malcolm Gladwell, a staff writer for The New Yorker • Subtitle is “The Power of Thinking Without Thinking” • Subconscious is better at realizing something quickly than conscious is at realizing it slowly • This explains how we identify “smelly code” • Amateurs have a hard time explaining it; experts do not
void DoStuff1() { int temp; // Do stuff here } void DoStuff2and3() { int temp, temp2; // Do more stuff } int DoLotsMore(int x) { // Encapsuplate more // changes here } Long Method What smells in here? void funcA() { int temp1, temp2, temp3; // Do stuff with temp1 … … // Do stuff with temp2 // and temp 3 … … //Do lots more stuff } Extract Method
Contents • Defining Refactoring • Defining Blink • Identifying types of “smelly” code • Learning refactoring solutions for this code • Deciding when and when not to refactor • Understanding the role of testing • Learning about tools available for refactoring • Breaking down examples throughout
When to refactor? • At any time, but only in short bursts as needed • 3 strikes, you refactor • Write it. Good job! • Second time, read and wince at duplication or poor structure • Third time, get fed up and refactor • When modifying any existing code by adding functionality, fixing bugs, or during code reviews
When not to refactor? • Database support often means being tied to a schema • Either abstract this away or don’t refactor • Public interfaces should not change, published interfaces cannot change • Make the old function call the new one • Trying to fix inherently flawed design • When code is beyond help • When approaching a deadline
Design and Performance • Refactoring complements upfront design • Software is malleable so do it simply first and then refactor in flexibility as needed • Find a reasonable solution, not the solution • Most of the time, the more complicated, flexible solution is overkill • Performance suffers from refactoring, right? • Not necessarily; according to Demeyer, modern compiler optimizations make virtual functions equal to branching • Doesn’t matter most of the time • Can concentrate on optimization in small, well-defined areas • Binary refactoring (Tilevich, Smaragadakis) – WHAT?!?! – is exclusively for performance
Binary refactoring: a study in contradictions • “Premature optimization is the root of all evil.” – C.A.R. Hoare • Money, Microsoft and MU are finally off the hook • Not to increase performance, but to not force source code changes to increase performance • Example 1: Objects that make sense to be stored in a database as a whole but only parts need to be transmitted • Example 2: Replace virtual function call with static or inline function call
Large Class What smells in here? See Example Extract Class or Extract Subclass
Contents • Defining Refactoring • Defining Blink • Identifying types of “smelly” code • Learning refactoring solutions for this code • Deciding when and when not to refactor • Understanding the role of testing • Learning about tools available for refactoring • Breaking down examples throughout
How to test? • Critical since functionality must remain the same • Development time in descending order: • Debugging • Analysis & design • Writing code • JUnit helps organize testing code in classes and run suites of tests • Only for unit testing • Don’t try to get all the bugs; build tests that are easy to run and are designed to get most of the bugs
class newObj { public: int getParam1(); int getParam2(); char* getParam3(); float getParam4(); float getParam5(); void* getParam6(); } void funcA(newObj obj) { int temp1, temp2, temp3; // Do stuff with all // this data } Long Parameter List What smells in here? void funcA( int param1, int param2, char* param3, float param4, float param5, void* param6) { int temp1, temp2, temp3; // Do stuff with all // this data } Introduce Parameter Object
Contents • Defining Refactoring • Defining Blink • Identifying types of “smelly” code • Learning refactoring solutions for this code • Deciding when and when not to refactor • Understanding the role of testing • Learning about tools available for refactoring • Breaking down examples throughout
How are tools useful? “Can we fix it? Yes, we can!” • Refactoring Browser was originally designed for Smalltalk • Requires a program database and parse tree • Must also be accurate, speedy, undo-able, and integrated with other tools
Demonstration • Refactoring in Visual Studio 2005 with Visual Assist X (http://www.wholetomato.com)
void funcA(acctObj acct) { int payment; payment = acct.getPayment(); // More stuff with // payment } Class acctObj { … int getPayment(); //new! … } Feature Envy What smells in here? void funcA(acctObj acct) { int payment; payment = acct.getBalance(); payment /= acct.getTerm(); payment *= acct.getRate(); // More stuff with // payment } Extract Method -> Move Method
void funcA(acctObj acct) { animal.speak(); } Switch Statements What smells in here? void funcA(acctObj acct) { switch (getAnimalType()) { case DOG: bark(); break; case COW: moo(); break; // etc. } } Extract Method -> Move Method -> Replace Type Code with Subclass -> Replace Conditional with Polymorphism
More “smelly” code • Divergent Change – any change to handle a variation should change a single class and everything within that class • Extract Class • Shotgun Surgery – opposite of above; to accommodate a change, must make lots of small changes to different classes • Move Method, Move Field, Inline Class
Some more “smelly” code • Data Clumps – data (like children) enjoy hanging around in groups; move these to a new class • Extract Class, Introduce Parameter Object • Primitive Obsession – group related primitives in a function into a new class • Replace Data Value with Object, Replace Type Code with Class • Parallel Inheritance Hierarchies – special case of shotgun surgery where subclass of one class requires subclass of another class every time
Even more “smelly” code • Lazy Class – classes (like teenagers) enjoy doing nothing if given the chance; must pull its own weight • Collapse Hierarchy, Inline Class • Speculative Generality – somebody over-engineered or over-designed -> too complicated • Collapse Hierarchy, Inline Class, Remove Parameter • Temporary Field – a member variable is used in some cases but not others • Extract Class, Introduce Null Object
The last of the “smelly” code • Message Chains – object asks another object, which asks another object, … • Hide Delegate, Extract Method, Move Method • Middle Man – half of an object’s methods call other objects • Remove Middle Man, Inline Method, Replace Delegation with Inheritance • Inappropriate Intimacy – spend too much time delving into private parts • Move Method, Move Field, Change Bidirectional Association to Unidirectional, Extract Class, Replace Inheritance with Delegation • Alternative Classes with Different Interfaces, Incomplete Library Class, Data Class, Refused Bequest
Watch out for comments (huh?!?) • Comments are often used as deodorant on this smelly code • Refactoring eliminates the smelly code so that the comments are superfluous • Replace each commented block of code with a new method using Extract Method and Introduce Assertion
Bibliography • Demeyer, S., “Refactor conditionals into polymorphism: what’s the performance cost of introducing virtual calls?”, IEEE International Conference on Software Maintenance, Pgs. 627-630, 2005. • Fowler, M., Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999, First Edition. • Gladwell, M., Blink: The Power of Thinking Without Thinking, Back Bay Books, 2005, First Edition. • Tilevich, E., Smaragdakis, Y., “Binary refactoring: improving code behind the scenes”, International Conference on Software Engineering, Pgs. 264-273, 2005, ACM.