XNSIO
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

What is the Least I can do that is Sustainable and Valuable?

Thursday, January 29th, 2009

Very very powerful thought when starting something!

How much Upfront Thinking?

Tuesday, December 30th, 2008

How much upfront planning, analysis and/or design do you do on your projects?

For me the answer depends. The more complicated/complex and critical the project is less the amount of upfront thinking (planning, analysis and design), I tend to do. In my opinion, its not really a choice I have.

I can spend months drawing pretty pictures and arguing about it. But only when I start prototyping (exploring) I start to understand the problem at hand. Each prototype is used to jointly explore the idea with all the stakeholders. And after I’ve done a few small (1-2 week) prototypes, we (stakeholders and the team) can actually layout things involved on the project.

At this point we can break down the overall project into smaller chucks and deep dive into them one by one (breadth first) or little by little at a time (depth first). In a way this is my planning, analysis and design process. Of course they don’t stop here, its just the beginning.

Fluent Interfaces improve readability of my Tests

Saturday, December 27th, 2008

Recently I was working on a Domain Forwarding Server. For Ex. if you request for http://google.com and Google wants to redirect you to http://google.in, then this server handles the redirection for you. There are many permutations and combination of how you want to forward your domain to another domain.

First pass, I wrote a tests:

1
2
3
4
5
6
7
8
@Test
public void permanentlyRedirectDomainsWithPath()  {
    when(request.hostName()).thenReturn("google.com");
    when(request.protocol()).thenReturn("HTTP/1.1");
    when(request.path()).thenReturn("/index.html");
    domain.setDomain("google.com");
    domain.forwardPath(true);
    domain.setForward("google.in");
9
    response = service.processMessage(request);
10
11
12
13
    assertStatus(StatusCode.PermanentRedirect);
    assertLocation("google.in/index.html");
    assertStandardResponseHeader();
}

Note that since the request is an expensive object to build, I’m stubbing it out. While domain is more of a value object in this case, so its not stubbed/mocked out.

This test has a lot of noise. All the stubbing logic was just making this test very difficult to understand what was going on. So I extracted some methods to make it more meaningful and hide the stubbing logic.

1
2
3
4
5
6
7
@Test
public void permanentlyRedirectDomainsWithPath()  {
    setDomainToBeRedirected("google.com");
    setDestinationDomain("google.in");
    shouldRedirectWithPath();
    setHostName("google.com");
    setPath("/index.html");
8
    response = service.processMessage(request);
9
10
11
12
    assertStatus(StatusCode.PermanentRedirect);
    assertLocation("google.in/index.html");
    assertStandardResponseHeader();
}

Looking at this code it occurred to me that I could use Fluent Interfaces and make this really read like natural language. So finally I got:

1
2
3
4
@Test
public void permanentlyRedirectDomainsWithPath()  {
    request("google.com").withPath("/index.html");
    redirect("google.com").withPath().to("google.in");
5
    response = service.processMessage(request);
6
7
8
9
    assertStatus(StatusCode.PermanentRedirect);
    assertLocation("google.in/index.html");
    assertStandardResponseHeader();
}
10
11
12
13
14
private ThisTest request(String domainName) {
    when(request.hostName()).thenReturn(domainName);
    when(request.protocol()).thenReturn("HTTP/1.1");
    return this;
}
15
16
17
private void withPath(String path) {
    when(request.path()).thenReturn(path);
}
18
19
20
21
private ThisTest redirect(String domainName) {
    domain.setDomain(domainName);
    return this;
}
22
23
24
25
private ThisTest withPath() {
    domain.forwardPath(true);
    return this;
}
26
27
28
private void to(String domainName) {
    domain.setForward(domainName);
}

Finally after introducing Context Objects, I was able to make the code even more easier to read and understand:

1
2
3
4
5
6
7
8
9
@Test
public void redirectSubDomainsPermanently() {
    lets.assume("google.com").getsRedirectedTo("google.in").withPath();
    response = domainForwardingServer.process(requestFor("google.com/index.html"));
    lets.assertThat(response).contains(StatusCode.PermanentRedirect)
                             .location("google.in/index.html").protocol("HTTP/1.1")
                             .connectionStatus("close").contentType("text/html")
                             .serverName("Directi Server 2.0");
}

Self Documenting Code Example

Saturday, November 8th, 2008

Yesterday a colleague @ Directi was writing some code and was very unhappy about the code. He was not sure how to write the following method without having to add a comment to explain the rationale behind the code’s logic.

1
2
3
4
5
6
private HttpSession renewSession (HttpServletRequest request, HttpServletResponse response)
{
  HttpSession session = webUtils.getSession(request, response);
  session.invalidate();
  return webUtils.getSession(request, response);
}

The method name expressed what the code was doing (renewing an existing session) but the “why” it was doing what it was doing was missing. The why is very important for someone to understand. This method was invoked from the following method:

1
2
3
4
5
6
void createAuthenticatedSessionUsingAuthenticatedEntity (HttpServletRequest request, HttpServletResponse response)
{
  HttpSession session = renewSession(request, response);
  AuthenticationInfoBean authInfoBean = authUtils.getAuthInfoBean (request);
  session.setAttribute(getAuthenticatedUserBeanKey(), authenticatedBeanCreator.create(authInfoBean.getUsername(), authUtils.getValidatedEntity(request)));
}

One option was to rename renewSession method to renewUnAuthenticatedSessionToEliminateSesionFixationByInvalidatingSession. But in the context where this method was used, it would be too much noise. Not always I’m interested in how and why the session is renewed.

Another option is to write a JavaDoc for the renewSession method. Personally I hate JavaDocs and I was interested to find a way to eliminate that. So I asked the developer to first write the JavaDoc to express what he wanted to express. He wrote:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* This method retrieves the unauthenticated session, then invalidates the session to eliminate session fixation issue and creates a new authenticated session.
* @param request HttpServletRequest
* @param response HttpServletResponse
* @return HttpSession Authenticated Session.
*/
private HttpSession renewSession (HttpServletRequest request, HttpServletResponse response)
{
  HttpSession session = webUtils.getSession(request, response);
  session.invalidate();
  return webUtils.getSession(request, response);
}

Now looking at the comment it was easy for me to figure out how to write the code such that the comment is not required. This is what we ended up creating.

1
2
3
4
5
6
7
8
9
10
11
private HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
{
  HttpSession unauthenticatedSession = webUtils.getSession(request, response);
  invalidateSessionToEliminateSesionFixation(unauthenticatedSession);
  return webUtils.getSession(request, response);
}
 
private HttpSession invalidateSessionToEliminateSesionFixation(HttpSession session)
{
  session.invalidate();
}

OR

1
2
3
4
5
6
private HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
{
  HttpSession session = retrieveUnAuthenticatedSession (request, response);
  eliminateSesionFixationByInvalidatingSession (session);
  return newlyCreatedAuthenticatedSession (request, response);
}

Again its arguable if writing code this way is much better that writing a small JavaDoc comment. As a rule of thumb, I always prefer self-documenting code over code which needs comments to support it. The real problem comes from the fact the comments soon fall out of place with the code. And why spend all the extra time maintaining code, its comments and also making sure they are in sync.

Throwing Away Code

Tuesday, October 7th, 2008

After burning my hands several times, I have concluded that

Throwing away code regularly will save a lot of time, effort, frustration, etc in the long run

Also

Throwing away code is an effective and efficient way to achieve Simple Design

Hence I propose, we add “Throwing away code” as a practice under the Simple Design, XP practice.

Mother of all Software Design Principles

Wednesday, September 24th, 2008

Design is the art of making constant trade-off decisions; Good Design has balanced Trade-offs!

The problem with design, as with life is that …… You can’t have it all!

Its easy to stick with extremes (complete upfront design v/s  code & fix style design), but its really hard to strike a balance (just enough or just in time design). Just enough is relative and means different things to different people. Also varies from context to context. Just enough design in one context can mean over-engineeing in another context.

Also, there is no ONE way of doing things. There are always options when it comes to designing software and one has to choose a approach that makes most sense. Is that the best design? Do you really need the best design? Its always easy to find a better design in retrospect.

Hence I say, the only Universal truth is that there are no Universal truths. Even law of gravity does not apply universally.

Micro-Design v/s Macro-Design v/s BUFD

Monday, September 22nd, 2008

My 2 cents to help with all the confusion out there with the word Design. (when I say Design, I really mean Object Oriented Design).

When we are developing and hence designing using Test Driven Development (TDD), the meaning of the word design is very different from what it means in the context of Big Upfront Design (BUFD). Even if we are not referring to BUFD, the amount of design required can vary significantly. Some people even challenge the whole notion of design being different from code. There has been (and will continue to be) a disagreement regarding how much to design before writing code?

Of late I find myself using the phrase micro-design to refer to the baby steps in the evolutionary design process, the kind of design that is really driven by the unit tests. While micro-design is very important and an integral part of development, there are times when you need a slightly bigger picture. For Ex. sometimes a feature can span across the software system and scope of this design is slightly more than micro-design, but very less compared to BUFD. I refer to the design step of this scope in the evolutionary design process as macro-design. I find prototypes and acceptance tests are really great at driving macro-design.

I find it really useful to call out to developers that this is micro-design step v/s this is macro-design step v/s this is BUFD.

Unit Tests Validates Micro-Design

Monday, September 22nd, 2008

I’m about to make a rather controversial statement now: “Developers who use purely inside-out avatar of TDD, .i.e. use unit tests to drive their development, are really using tests to validate their design and not so much to drive the design”.

The reason I think this way is because in my experience, developers who drive development using unit tests already have a mental model, whiteboard model, CRC card model, etc. of their design. Unit tests really helps them validate that design. (This is clearly not same as BUFD (Big Upfront Design). In this context its micro-design, design of a small feature not the whole system). Of course there is some amount of driving the design as well. When developers find out that the design they had thought about does not really fit well, they evolve it and use unit tests to get feedback. But as you can see the intent is not really to discover a new design by writing the test first.

Is this wrong? Is this a sign that you are a poor developer? Absolutely no. Its perfectly fine to do so and it also works really well in some cases for some people. But I want to highlight that there is another approach to influence design as well.

In my experience, using an Acceptance tests helps better with driving/discovering micro-design. When your test is not in the implementation land, when its in the defining-the-problem-land, there are better chances of tests helping you to discover the design.

While TDD is great at driving/discovering micro-design, Prototyping is great as driving/discovering macro-design.

Summary of Styles of TDD workshop

Monday, September 22nd, 2008

At the Agile 2008 conference in Toronto, Bill Wake and I faciliatated a workshop on Styles of TDD (had to change the name from “Avatars of TDD”, based on feedback from people that most people don’t know the word Avatar). You can find a quick summary of the workshop here : http://agile2008toronto.pbwiki.com/Styles-of-TDD

When does Design begin?

Sunday, September 21st, 2008

I used to think that Design really beginnings once you have the requirement (user story) in place. Over the years, I have learnt that design is not just a phase on the project. Design is quite intertwined with other activities we do during development and is spread through-out the life-cycle of a project. IMHO, there’s no discrete point in time on your project when you are not designing. To put some meat to this topic, let me share a recent experience with you which will reinforce my point.

A good buddy of mine, (who had been a TDD practitioner for a while) called me up and told me to have a look at some code. He was not very comfortable with the way the classes were interact with each other (design smell). I looked over the code and I agreed with him. The classes depended on each other in an awkward manner. Then I looked at the tests and I felt the tests were not really right. Could not tell why exactly, but something did not seem right. I asked him to show me the user story he was working on. I looked at the story and I realized what was happening. The way he had his story broken down, was quite different from how I would break it.

So I asked him, if I could give a shot at breaking down the stories differently. We spent some time and came up with user stories that kind of make sense to me. That was followed by a short TDD sessions. We got rid of the awkward class dependency issue, but ran into another issue. Well that’s not the point. What’s important here is, we realized that breaking down the user story differently lead to a very different design. What does this mean? We concluded saying, the way we create our user stories can impact the software design. So by breaking the user stories differently one can lead to a different design. Hence while we are creating/breaking down user stories, we are making design decisions.

We can take this one step further. I’ve had experience on real projects where depending on the order in which we developed our stories, the design evolved differently. Jeff Patton likes to say that when the stakeholders take a decision of building software to solve a business problem, they have made a design decision.

Conclusion: Design begins way before we think it actually does. We know Prototyping and TDD is a great way to validate those design decision. Don’t forget the best feedback is got when actual user use your software. Hence try to realse as frequently as possible. May be on a daily basis.

    Licensed under
Creative Commons License