Showing posts with label refactoring. Show all posts
Showing posts with label refactoring. Show all posts

5/16/2009

TDD: The Rhythm


Good TDD, well real TDD, provides the team with a heartbeat.

Everyone has a heartbeat, you know what it's like: continuous and clear, smoothly flowing, subtle yet ever so present and soothing. Its unlikely that you're explicitly listening to it, but you are without doubt subconciously aware of the supreme comfort and reassurance that heartbeat provides you each and every minute of your day. It keeps you alive!

Same is true with software development. And while Iterations, Stand-ups, and CIT no doubt provide an essential macro-heartbeat, those things aren't what give us that minute to minute assurance analogous to our human heartbeat. That's where TDD comes in - true TDD provides us that comforting development heartbeat to actually get us productively and happily through the day.

It provides the transition from story card to failing storytest (acceptance test). Then from failing storytest to the first failing microtest (unit test). Then minutes later to the first passing microtest. Then minutes later to the next failing microtest, then the next passing microtest, and our first refactoring. Then minutes later to our next quick cycle of "red/green/refactor". Then within an hour our first check-in. Then a few more "red/green/refactor" cycles and another checkin. And before you know it, after one of those cycles, boom, a passing storytest! A high-five and a final checkin, then home by 6 to see the kids.

Do you hear it? Thum-THUMP, Thum-THUMP, Thum-THUMP...RedBar-GREENBAR, RedBar-GREENBAR, RedBar-GREENBAR...
A development heartbeat.

It's this rhythm that guides you, that keeps you on track. Its what gives you the constant feedback to know, at every step of the way, that you're growing the right design, that you're satisfying the customer's needs, and that you haven't broken any windows. It's what allows you to move freely and move fast. It's this rhythm that makes you feel good. It's this rhythm that makes you feel alive and happy.

Ask anyone whose felt it. Once you've actually truly experienced this rhythm - this heartbeat - I assure you, just as with your human heartbeat, you'll find it unbearable to ever live without.


4/02/2009

PropertyFor Sale

Properties. And, Java. Lots of languages really, but let's look at Java. Every Java (and other langs too) application of any size is going to be using some properties. Typically, they'll be held in a "myspecializedvalues.properties" file, but not necessarily. For this example, let's assume you are using such a file (and can then thus use Java's built-in property management mechanism), but again, its not really the point. And this approach can be applied no matter what format you choose to store your properties.

The point of this is to show you a better way to manage - a better way to encapsulate and access - your properties so that the implementation is hidden behind an expressive interface, easy for anyone to understand and use.

The point is to show the PropertyFor class, and to tell you why its better than what you probably have in place.

So, this example has a strategy factory class that needs to make its decisions based on a property setting, this property having a true/false (boolean) value. It starts off looking like this:
public class GeneratorFactory {
public String propFileName =
"ELearningSettings.properties";

public GenerationStrategy projectGenerationStrategy() {
if (shouldIgnoreCode())
return new GenerateWithoutCode();
else
return new GenerateWithCode();
}

private boolean shouldIgnoreCode() {
Object valueObj = getProperty("CODE_IS_USELESS");
if (valueObj != null)
return Boolean.parseBoolean((String)valueObj);
return false;
}

private Object getProperty(String key) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(propFileName));
} catch (IOException e) {
throw new RuntimeException(e);
}

return properties.get(key);
}
}

You'll hopefully notice something about this factory. First, it's primary responsibility is to serve up the correct strategy to its caller. Of course though, you'll also notice that not only does this class do its primary purpose, but it also has a lot of low-level knowledge about how to obtain the information it needs to make its decision. It knows all sorts of things about icky java property mania.

Now, if this is the lone property in your system, than maybe this is okay and doing any kind of extraction here might be YAGNI (you might though, even if that is the case, be bothered by that fact that this class clearly violates the SRP, nonetheless...).

Of course though, this is not the case, and so let's assume that although this is the only class you see in this example there are in fact more properties in your system and more users of them.

So, the logical thing to do is to extract that property reading management into its own class, happy to have its sole responsibility being providing property values. You do so, and end up with this new "Settings" class:
public class ELearningSettings {
public String propFileName =
"ELearningSettings.properties";

public Object getProperty(String key) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(propFileName));
} catch (IOException e) {
throw new RuntimeException(e);
}

return properties.get(key);
}
}

public class GeneratorFactory {
public GenerationStrategy projectGenerationStrategy() {
if (shouldIgnoreCode())
return new GenerateWithoutCode();
else
return new GenerateWithCode();
}

private boolean shouldIgnoreCode() {
Object valueObj =
ELearningSettings.getProperty("CODE_IS_USELESS");
if (valueObj != null)
return Boolean.parseBoolean((String)valueObj);
return false;
}
}
You slap five with your pair and check in, this is much better! Now your factory can do it's job without having any internal worry about where the settings (properties) are really coming from or how they're implemented. Any other users of properties also get the same luxury. A big improvement, no doubt.

Many systems I've seen have figured this much out, and have this in place. A "Settings" class that hides the details of how to look up properties, all you have to give it is the key to the property you want.

But, this has limitations.

First, and as many will figure out and solve on their own, a sprawl of the property key strings hard-coded in the various users of the properties. You want to change this key? Have fun chasing all the uses down. Of course you could create a constants file for these keys, and have the callers only know the constants (which, in Java at least, provides the big benefit of being able to leverage you IDE when you want to change its name), but is that really enough?

Second, yes your factory doesn't know about "ELearningSettings" or the "java...Properties" guts, but it does still have the job of knowing the format of these property values ('Object' in this case) and how to turn that into what it really wants, a boolean.

Third, particularly if haven't created a constants file (in response to the first problem), how easy is it for future developers to go to one place and see all the possible properties/settings the system has available for them?

There may be more limitations, but that's enough for me.

So, our answer to each of these questions is where the magic happens, the MBark of this article. We evolve our generic "Settings" class into a domain-friendly "PropertyFor" class:
public class PropertyFor {
public static String propFileName =
"ELearningSettings.properties";

public static boolean shouldIgnoreCode() {
Object valueObj = getProperty("CODE_IS_USELESS");
if (valueObj != null)
return Boolean.parseBoolean((String)valueObj);
return false;
}

private static Object getProperty(String key) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(propFileName));
} catch (IOException e) {
throw new RuntimeException(e);
}

return properties.get(key);
}
}

public class GeneratorFactory {
public GenerationStrategy projectGenerationStrategy() {
if (PropertyFor.shouldIgnoreCode())
return new GenerateWithoutCode();
else
return new GenerateWithCode();
}
}
What did we do here? Well, we've taken all the knowledge highlighted above as our limitations and removed it from our factory (really, from all of the users of settings), and put it into our "Settings" class - which, as a result, now becomes a more useful, expressive PropertyFor utility.

So, you'll see our factory now has to worry just about choosing a strategy, and no longer has any overhead related to obtaining the values it needs to make its decision. More specifically, it doesn't know where the settings come from, doesn't know the details of how to access them or the keys that identify them, and it doesn't know what raw format they come in. The factory knows it needs the boolean value of whether or not to "ignore code", and it gets that in one clear, simple line of code.

Further, you've got the beauty of expressive methods on singular class to be very domain-centric in assisting other programmers to access the available setttings/properties for your system - these methods, not only being clearly and expressively named, but also being typed appropriately for ultimate ease to the consumer. And of course, when you need to change the name of the setting and/or the name the callers know it by, no problemo.

So, that's really the main meat.

For good measure though, we take a moment to improve the design of our PropertyFor class. First, this isn't the only boolean setting we have (use your imagination) so we should have a nice clear reusable method to handle our boolean typed settings:
public class PropertyFor {
public static String propFileName =
"ELearningSettings.properties";

public static boolean shouldIgnoreCode() {
return boolanValueFor("CODE_IS_USELESS");
}

private static boolean boolanValueFor(String key){
Object valueObj = valueFor(key);
if (valueObj != null)
return Boolean.parseBoolean((String)valueObj);
return false;
}

private static Object valueFor(String key) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(propFileName));
} catch (IOException e) {
throw new RuntimeException(e);
}

return properties.get(key);
}
}


And then, it really is pretty inefficient of us to read the properties file over and over, so let's take care of doing that just once and being done with it:
public class PropertyFor {
public static String propFileName =
"ELearningSettings.properties";

private static Properties properties;
static {
loadProperties();
}

private static void loadProperties() {
properties = new Properties();
try {
properties.load(new FileInputStream(propFileName));
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public static boolean shouldIgnoreCode() {
return boolanValueFor("CODE_IS_USELESS");
}

private static boolean boolanValueFor(String key){
Object valueObj = properties.get(key);
if (valueObj != null)
return Boolean.parseBoolean((String)valueObj);
return false;
}
}
So there you have it: PropertyFor.

And, of course, this isn't a post about TDD, but here is the test that was in place and passing before and after any of these refactorings went down:
public class GenerationStrategyFactoryTest {
@Test
public void needingACodelessStrategy() {
propertiesFileIs("CodelessGenerationStrategy");
assertTrue(strategy() instanceof GenerateWithoutCode);
}

@Test
public void needingACodeStrategy() {
propertiesFileIs("IncludeCodeGenerationStrategy");
assertTrue(strategy() instanceof GenerateWithCode);
}

private void propertiesFileIs(String fileNameBase) {
String filePath = "testdata/"
+ fileNameBase + ".properties";
PropertyFor.propFileName = filePath;
}

private GenerationStrategy strategy() {
return new GeneratorFactory().
projectGenerationStrategy();
}
}
As an exercise, go ahead and write the test you think I have for the PropertyFor class, because of course you know I do!


ps// I'm really not liking this code highlighter library so far. Any other Bloggers have good suggestions for a good library?!?

3/22/2009

TDD: The Synergy


TDD. What does this stand for?

Test Driven Development.

Said another way: Development, driven by tests.

Notice, the acronym doesn't stand for test driven design. Not test driven analysis. Not test driven coding. Nope, not even test driven testing. It is, again, test driven development.

TDD is not a "task". It's not a thing we do in addition to doing design, or in addition to writing production code, or in addition to "writing" stories. Rather, TDD it is the way we design, the way we write code, the way we define a story. It is the way we do development.

When done well, TDD exists at root of nearly everything we do in our agile team - it is the team's minute-to-minute comforting heartbeat.

TDD means that "writing a story" equates to specifying in an automated acceptance/story test (most often using FitNesse, Selenium, WaTiR, or something similar) "what it will look like" for a story to be working once we've implemented it. How the new application feature monickered on the story card must behave for it to be DONE.

TDD means that "designing" equates to specifying in an automated unit/micro test (most often using a member of the xUnit family of tools) "what it will look like" for any particular object to work once we've implemented it. In other words, what the expected behavior of that object is.

TDD means that "coding" equates to letting that unit test tell us when we've written working production code. Possibly more importantly, it means that "coding" equates to letting those passing unit tests ensure that our object continues to work (satisfy it's expected behavior) while we mercilessly refactor that object to keep it super clean and expressive.

And, in case you didn't notice in the above assertions, it means that our development is driven by tests. This means that the test is written first. The existing [failing] test is what drives us to conjure up production code. The test is the only reason for us to write a line of code. It's the only way we know what code to write - the test is our specification. Yes, we can write production code first then try to write a unit test to verify it's implementation, but, in addition to the mechanics of that likely being extremely difficult and counter-productive, that's simply not TDD.

Make no mistake about it. True TDD, at the acceptance (Story/Service) test level, is an act of analysis. And true TDD, at the micro (unit/object) test level, is an act of design. In a single statement: True TDD is much less an act of verification (as the "test" part of the name might accidentally and incorrectly imply) as it is an act of specification.

In summary, TDD provides the fundamental synergy between and foundation for all of our development "tasks" that enables us to truly build the right software and to build the software right. It ensures quality2 - which, in the end, is the only true way for us to go fast and go fun.



** Upon further review, authors are changing the catchy phrase "ensures quality2" to the more appropriate phrase of "ensures high quality and low shittiness"

3/02/2009

Nutshells: Why TDD?

So, ya need that techie-friendly quick-pick-list to explain to someone why your project simply cannot live another second without TDD? I know I did, so I created one. And I'd like to share it with you faithful readers.

Confidence & ProductivityToday
  • Immediate feedback, ie. "cookies": Green bars that give me full confidence in what I’m coding, or in other words, meeting requirements with decreased bugs

  • A more efficient design:
    • Clear “expectations” (tests) drive my mind quickly and smoothly to solutions (algorithms)
    • Good public interfaces – my tests make me “eat my own dog food”
    • Simplicity – I’ve coded only what was needed to pass the tests
  • A more effective design: in order to write software that is effectively tested in this manner, I’m naturally encouraged to ultimately write more cohesive and less coupled code
  • Test “protection”: “my tests” give me freedom to refactor mercilessly to create a more expressive, readable code-base while I’m coding
  • And then even more Test “protection”: “all the tests” allow the build to silently ensure that today’s collective changes across the group haven’t broken any windows

Confidence & Productivity … Tomorrow
  • Fact: addressing yesterday's bugs exponentially decreases today's productivity...unless:
    • yesterday 's TDD decreases (if not nearly altogether removes) yesterday's bugs

  • Fact: most bugs occur upon changing an existing code-base...unless:
    • Today’s [automated] tests become your safety net tomorrow
    • Growing test suite allows build to be the perpetual “silent police”

  • Fact: easy to understand my design; hard to understand your design...unless:
    • Today’s [expectation-based] tests become your documentation tomorrow
    • My expressive code is easy for you to understand tomorrow

  • Fact: “code rot” (poorly factored code) slows development over time...but:
    • My tests force me to keep my design well-factored – forever!

  • Fact: “paper documentation” gets outdated (and lies!) over time...in contrast to:
    • Automated Storytests: up-to-date, runnable “what it does” documentation (analysis)
    • Automated Microtests: up-to-date, runnable “how it does it” documentation (design)

Of course, I'm not perfect, and feedback is king. So, please, pretty please with sugar on top, let me know how you think this list can be improved!

 
/* */