“Refactoring” Notes

I’m not going to bother with a review of Martin Fowler‘s Refactoring: Improving the Design of Existing Code. It’s good enough that its catalog, available in expanded form online, now provides the definitive vocabulary shared by dozens of refactoring tools across nearly every major development platform. Though I was already familiar with the majority of the catalog, I thought it would be worth reading the other chapters, the notes from which you will find below with my additions indicated with emphasis. I’ve also included thoughts on various entries in the catalog.

Principles in Refactoring

  • 58: You don’t decide to refactor, you refactor because you want to do something else, and refactoring helps you do that other thing.
  • 62: Beck – Maintaining the current behavior of the system, how can you make your system more valuable, either by increasing its quality, or by reducing its cost. … Now you have a more valuable program because it has qualities that we will appreciate tomorrow. … There is a second, rarer refactoring game. Identify indirection that isn’t paying for itself and take it out.
  • 62: Problems with Refactoring
    • Don’t know limitations
    • Is refactoring because a tool tells you to a bad reason?
  • 65: Modify your code ownership policies to smooth refactoring.
  • 66: Code has to work before you refactor.
  • Ward Cunningham: Unfinished refactoring = technical debt.
  • 68: You still think about potential changes, you still consider flexible solutions. But instead of implementing these flexible solutions, you ask yours, “How difficult is it going to be to refactor a simple solution into the flexible solution?” If, as happens most of the time, the answer is “pretty easy,” then you just implement the simple solution.
  • 70: Changes that improve performance usually make the program harder to work with.
  • If you optimize all code equally, you end up with 90 percent of the optimizations wasted, because you are optimizing code that isn’t run much.

Bad Smells in Code

An expanded catalog of code smells is available online.

  1. Duplicate Code
  2. Long Method
  3. Large Class
  4. Long Parameter List
  5. Divergent Change
    • One class that suffers many kinds of changes
  6. Shotgun Surgery
    • One change that alters many classes
  7. Feature Envy
  8. Data Clumps
  9. Primitive Obsession
  10. Switch Statements
  11. Parallel Inheritance Hierarchies
  12. Lazy Class
  13. Speculative Generality
  14. Temporary Field
  15. Message Chains
    • a.k.a. Law of Demeter
  16. Middle Man
  17. Inappropriate Intimacy
    • Circular Reference => Change Bidirectional Association to Unidirectional
  18. Alternative Classes with Different Interfaces
  19. Incomplete Library Class
    • Introduce Foreign Method => Extension Methods
  20. Data Class
    • Favor setters and encapsulated collections
    • Very OO-centric – FP would argue that immutable data classes are preferred
    • Hide Method => Immutability
    • 87: “Data classes are like children. They are okay as a starting point, but to participate as a grownup object, they need to take some responsibility.”
  21. Refused Bequest
    • Smell is stronger if the subclass is reusing behavior but does not want to support the interface of the superclass. (NotSupportedException)
    • Apply Replace Inheritance with Delegation
  22. Comments
    • 88: When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.

Building Tests

  • Tests should be fully automatic and self-checking.
  • Interesting that a distinction is drawn between unit and functional tests, but there’s no mention of integration tests as middle ground
  • 97: “When you gget a bug report, start by writing a unit test that exposes the bug.”
    • This is my #1 use case for test-first
  • 98: “The key is to test the areas that you are most worried about going wrong.”
  • 101: “Don’t let the fear that testing can’t catch all bugs stop you from writing the tests that will catch most bugs.”

If this is the first you’ve read of unit testing, check out a book dedicated to the subject like Pragmatic Unit Testing.

Catalog Notes

  • Composing Methods
    • Replace Method with Method Object
      local variables => method object fields to facilitate extracting methods
  • Moving Features Between Objects
    • Introduce Foreign Method = Extension Methods
    • Introduce Local Extension = Subclass or Proxy
  • Organizing Data
    • Replace Data Value with Object
      replace primitive with a type that means something (decimal => Money)
    • Replace Type Code with State/Strategy
      inheritance is often abused, but this is one of its best use cases
  • Simplifying Conditional Expressions
    • Introduce Null Object
      OO approach to avoiding null checks, also not to be abused
  • Making Method Calls Simpler
    • Separate Query from Modifier
      mutation and query operations don’t mix
    • Replace Parameter with Method
      this rarely applies to new code, but rather is found in methods that have evolved over time
    • Hide Method
      • Related: Remove from Interface — useful to let a method “hide in public” for easier testing without cluttering up its expected usage as implementer of an interface
    • Replace Error Code with Exception
      if a circumstance is truly exceptional, exceptions are often better than error codes…
    • Replace Exception with Test
      …but if it’s not exceptional, don’t incur the overhead; for example, return a Null Object
  • Dealing with Generalization
    • Extract Subclass, Superclass and Interface
    • Collapse Hierarchy
    • Form Template Method
    • Replace Inheritance with Delegation
    • Replace Delegation with Inheritance

Big Refactorings

  • 359: “Do as much as you need to achieve your real task. You can always come back tomorrow.”
  • 360: “You refactor not because it is fun but because there are things you expect to be able to do with your programs if you refactor that you can’t do if you don’t refactor.”
    • I need to remember this!!

These are hard to identify, but provide the biggest return on investment. Think of them as high-level goals accomplished through low-level changes from the above catalog.

  • Tease Apart Inheritance
  • Convert Procedural Design to Objects
    • Also, Convert to Functions
  • Separate Domain from Presentation
    • MVP, MVC, MVVM…use something!
  • Extract Hierarchy
Advertisements
Posted in Books, General. Tags: . Comments Off on “Refactoring” Notes

So what’s the symbology there?

[This is the first in a series of posts I will be writing as part of a graduate course on Emerging Practices in Human-Computer Interaction, cross-posted from our class blog. I’ll do my best to make the posts stand on their own outside of course content, but feel free to ask for clarification if I fail to do so.]

As I read the opening chapter of Paul Dourish‘s Where the Action Is, I couldn’t help but pause to reflect on the phases through which interaction has evolved over the years: electrical, symbolic, textual and graphical. Dourish characterizes the transition between phases as “a general trend that emerges in a number of different ways”(7). What he didn’t mention is that each new interaction paradigm has served to supplement the former in a continual coevolution. This coevolution will be essential as we try to make the most of the new devices and manifestations of computational power, particularly with relation to multi-core and distributed processing.

As a mathematician and language geek, I’m most drawn to interaction optimizations at the symbolic level. Through my programming career, I’ve been exposed to dozens of symbolic abstractions, ranging from Logo and my TI-85 to academic amusement with Scheme to “real-world” languages like C and Java. For the most part, however, the languages have been more similar than different. And with the exception of a course on functional languages, the style of programming was always the same: tell the computer how to push these bits around. For the majority of problems, that was simple enough, particularly with the steady march of CPU speeds in step with Moore’s Law.

Well physics decided to step in the way of our 20-GHz CPUs, leaving us instead with dual- and quad-core systems. There’s still an increase in processing power, but taking advantage of it requires new ways of thinking. Among these are various new (or new-again) symbolic abstractions that will be essentially to get developers back to the point where the electrical systems are sufficiently hidden that we can get on with the real work of building the next generation of textual and graphical interfaces. As a developer on the Microsoft platform, there are two in particular that are of interest: Axum and F#.

Axum

According to Microsoft, “Axum is a language that builds upon the architecture of the Web and principles of isolation, actors, and message-passing to increase application safety, responsiveness, scalability, and developer productivity.” In other words, it’s a domain-specific language (DSL) built specifically for scenarios involving distributed and concurrent computation. I haven’t built anything with it yet, and at this point it remains very much experimental, but the concept has a lot of promise to faciliate the creation of applications and frameworks that can seamlessly handle the new architectures that have emerged. For more information, check out the Axum page on MSDN.

F#

Functional languages have been around for a very long time, and they are based on the lambda calculus which has been around even longer. But only recently have they started to come back into mainstream view, due in part to new functional languages for the major development platforms: Clojure and Scala for the Java Virtual Machine, and F# for .NET. The other reason for this comback is the ease with which functional languages handle the problem of concurrency through the use of immutable values and data structures. These languages also provide other higher-level abstractions that move developers away from specifying “how to push these bits around” and more toward specifying what they are trying to accomplish.

In both cases, there is clear value in solving the difficult problems once and letting symbolic abstractions shield the rest of us from ever having to think about it at a low level. It will always be necessary to have some knowledge of what’s happening behind the scenes, just as managed memory doesn’t free the developer from memory considerations completely. But leaning on advanced symbolic abstractions is one more way to advance the state-of-the-art in HCI.

Posted in General. Tags: . Comments Off on So what’s the symbology there?

Resistance is Futile

So I just got back from the Twin Cities SharePoint Camp where I had several interesting conversations that ended with more questions than answers, as I’ve found is often the case as a SharePoint developer. As much fun as it is pseudo-anonymously commenting on various blog posts, I’ve been frustrated for a while leaving URL blank. So at the urging of Raymond Mitchell, here I am. Blogger WordPress is probably temporary, but if I wait to put something “me” together it will probably never get off the ground. So without further ado, welcome to Solutionizing .NET!

Why Solutionizing? Well for the past several months I’ve been up to my neck in SharePoint as an application platform. And it has become increasingly clear that Solutions — limitations and MAKECAB.EXE aside — are fundamental to the process. However, a lot of questions remain as to how Solutions should be built and how their limitations can be overcome. This blog will be my humble attempt to answer some of those questions. I make no claims of expertise, just a desire to get better at what I do and contribute to the community that has been so helpful to me thus far.

Cheers ~
Keith

Posted in General. Comments Off on Resistance is Futile