Refactoring – An analysis of intent (Part II – Understanding)

December 29, 2007 at 4:21 pm 1 comment

Decorative PictureSummary: We can roughly taxonomize the type of understanding needed from source code by considering:

  • Whether the reader is trying to understand what code does or how it does it.
  • Whether the reader wants a vague or exact understanding.
  • What fraction of the code is the reader trying to understand. Are they just trying to understand a local area or are the trying to understand the program globally as a whole?

For each type of understanding, some types of refactoring may make understanding easier, whilst others may make it harder. This is particularly relevant for vague understanding and local understanding.

Regardless of what the reader is trying to understand, some things just make reading code easier. Writing code that is the same as – or analogous to – code that others have already written makes understanding a lot easier. Making code consistent allows the reader to remember a limited set of rules rather than actual details. Doing what people expect means they won’t be suprised and confused. With this is mind, we see that using patterns and idioms makes code a lot easier to read – provided that the reader knows the idioms and patterns. Some refactoring may be good at doing this – other refactoring might be bad…

Classifying the reasons for wanting to understand code When trying to understand code one normally has a purpose in mind. Some examples include:

  • To try to work out what a particular function does.
  • To help them fix a bug.
  • To understand the code so as to extend it.
  • To understand the code so as to reimplement it elsewhere.

One handwaving way of classifying the types of understanding that the reader is after is in terms of the three facets

  1. How vs What
  2. Vague vs Specific
  3. Local versus global.

Don’t worry, this isn’t quite so vacuous as it sounds…

What/How – Sometimes one is interested in the effects that running a piece of code has, whereas at other times one is more interested in exactly how a piece of code does something. For example, when fixing bugs “how” can become very interesting to you, but when you only want to use a class or function the “how” can become quite hideously dull. The relevant point here is that default source code is a lot worse at the “what” than the “how”.

Vague/Specific – Often, one definitely does not want to know the detail of how a program functions, rather one wants a vague understanding that lets you think about things. For example, if you are just skimming through libraries “Deals with network requests” could be a very useful description. It is to be noted that at times a vague understanding is needed before a precise understanding can be developed.

We can understand making something vague as meaning “replacing a specific fact with a class of possible facts such that our first fact is a member of it”, or “replacing a statement s with a statement that is implied by s but that s does not imply.” For example, instead of “My cat Jim” we might write “An animal”. The fact that a sentence or statement can be made more useful by having several possible interpretations is relevant – if only because it seems counterintuitive at first.

Local/Global (area of understanding) – The shape of the “topics one wants to understand” or the section of code one wants to understand can vary a lot. Sometimes one only wants to understand what a particular function does, whereas sometimes one will want to understand what a whole module does. At other times, you might want to understand a particular section of a module, like all the logging code or all the code related to accessing data.

Here are some examples of how these facets interact:How + Specific + Local: Understanding exactly how a section of a function works for debugging.

What + Vague + Global: Getting to the point where you can use an API by referring to documentation, i.e you know roughly what functions there are.

Now, let’s look at how this applies to refactoring.

Relevance of this classification to refactoring Classifying types of understanding is relevant to refactoring because different kinds of refactoring can improve certain species of understanding – but make other types worse. Each facet is considered in turn:“What” understanding As a rule, code seems to be very good at telling one how something is done, but not too good at telling someone what is happening. Succinct comments in headers files can be useful for this. I’ve heard that Eiffel has built in pre- and postconditions, which are probably useful for extracting the what from the how.Making names meaningful and “intent-revealing refactorings” probably make such understanding simpler.

“How” Understanding Code is probably quite good and saying how things are done, since this is all it specifies.

Vague Understanding. Vague understanding is improved by adding vague concepts or concepts that suggest how a section of code works, since then a reader can ignore the details where appropriate and just look at the vague concepts. This is perhaps best done through succinct comments which are separated from the code, but several types of refactoring can affect vague understanding.

One common refactoring consists of replacing meaningful subsections of a function with function calls with appropriate names. This allows the reader to ignore the implementations details and replace them with the vague mental reference to the function.

Another suggested refactoring is replacing subexpressions with appropriately named variables – again adding vague concepts that the reader may use.

We’d expect some refactorings might make vague understanding harder – though I can’t think of any at the moment – apart from those that make understanding harder in general.

Specific understanding. Understanding exact details is made easier by having the relevant details closer together, and with as little extraneous understanding in the way as possible.

Most encouraged types of refactoring makes this more difficult. For example, creating subroutines splits the program’s flow into several different places making it hard to follow execugtion.

Using inheritance – or polymorphism – or delegation – or dispatch tables – or function pointers – or in fact most things that seem elegant adds a layer of complexity to be understood before the function of the program can be comprehended. Also, this can make following the flow of the program rather convoluted.

Sometimes, certain refactorings can make something dynamic when it used to be static: for example the use of closures in python. This can require a reader to understand these mechanisms, whereas before they could have just found the appropriate section of the code and started to read.

Aspect-Oriented Programming doesn’t necessarily make understanding specific things more difficult, in fact it can make understanding certain details easier, though it makes understanding the general flow of the program more difficult.

Local Understanding The key to making understanding limited sections of the code easier is to require as little understanding of other sections of the code as possible, i.e severing links with other pieces of code and cutting down dependencies where possible. Programming by contract is quite good at doing this – this at leasts limits your understanding of other sections of code to their contracts. Similar cutting dependencies between different types of applications can make understanding the code for these applications easier.

Global Understanding There isn’t much one can do to make global understanding any easier or harder… as if someone seeks to understand everything they are going to have to understand ethe entire program.

Some general musing on understanding So far, we have only considered the types of understanding that people are after – not what makes understanding easy. The questions “What is understanding?” and “What affects the ease of understanding?” are potentially very hard questions – probably each deserving a couple of shelfs of books, but here we spend about 3 paragraphs.
Things are easier to understand and remember

  • If you’ve written them before.
  • If you’ve seen them before.
  • If you’ve seen something like them before.
  • If they are consistent (one only has to understand a rule once – and if you are using it all the time you are unlikely to forget it)

Things are quicker to understand if the reader doesn’t have to put much that is new into their head. If they do have to put something new into their head, it’s better that they use it a lot as then they are less likely to forget it.

Some refactoring can be helpful here by:

  • Setting up consistent patterns to aid memory. E.g naming conventions
  • Changing patterns to those that can be more easily recognized – i.e using idioms and patterns. An example of this might be to refactor code to use map and reduce rather that using a bespoke algorithm – provided programmers are familiar with this.

Idioms are quite interesting in this regard, because they simultaneously make some code easier to read for the experienced, and harder to read for others. For example, if the reader of the coder is incredibly familiar with C and has spent several months working on string parsing then changing:

c = 0;for(p = strtok(s, ";"); (*q++ = *p++) && p != ';' ; c++ );

to something that a lesser mortal could read without thought might be a bad idea.

A key point to remember in all of this is that what is easy to understand depends upon the reader in question. In a way, code itself isn’t well-written, but it is well written for a person and a purpose. An even more important point to remember is that code is written with an aim mind other than being read.


Entry filed under: Uncategorized. Tags: , .

Refactoring – An analysis of intent (Part I) Patterns – A list of forces

1 Comment Add your own

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

Trackback this post  |  Subscribe to the comments via RSS Feed

December 2007
    Jan »

%d bloggers like this: