Showing posts with label Design. Show all posts
Showing posts with label Design. Show all posts

Friday, 11 October 2013

About Myths


To every Myth there is always an equal destructive (Stupid) and opposite counter Myth:

Here are some Examples

Myth
You do not need to design up front
Counter Myth
Design is a one time effort which is best done before you start
Reality
You need to design some of your system up front and some of your system as you go. How much you need atg each stage depends upon your understanding of the problem, you technical skills & your system.


Myth
All user stories may be implemented independently from each other
Counter Myth
We must analyze all the dependencies between all features in order to lay out our critical path
Reality
There will always be some dependencies between different user stories, however a lot of those can be eliminated with some effort invested during story slicing. Those which are left are usually obvious enough for a reasonable team to deal with.


Myth
you don't need architects.
Counter Myth
A strong enough architect can design the system in such a way that anyone could implement it.
or
The architect doesn’t need to code
Reality
Every team needs to have strong design skills, when the projects becomes big enough a dedicated person (aka the architect) to help with the communication of the overall design and helping making sure everyone stays on the same picture is really important. However, the architect in order to be effective, needs to be involved in the day to day programming issues and challenges the team encounters. And at the end it will be the programmers that will do the implementation and they will adapt it according to their understanding so you better have a strong team as well.

Wednesday, 20 June 2012

Don’t Repeat Yourself–the story of a wasted hour

The DRY principle is kind of a known concept to most software developers. it goes hands in hand with “Minimize Duplication” (4 elements of simple design by Kent Beck) “Single Source of Truth” and probably some more of this kind.

But lets start with a story

I hate Wasting Time

This week I was sitting doing some pairing trying to setup their first Given-When-Test using nBehave. We went through the regular steps: creating a new empty project, setting up a new empty spec test running it seeing that it fails and started working on actually doing something meaningful by loading up the application DAL into the test context.

10 minutes into the process, executing what we had resulted in a very nice FileNotFoundException and some text talking about that the need to use a strong name assemblies only.

Great!

Of course Microsoft was generous enough to omit the name of the actual file (which probably would have saved us most of the time in fixing the problem and your time in reading all this) but anyway 1 hour later we noticed that the code base has several 3rd parties dll’s appearing in the wrong places and they were all checked into the source control AND to make things happier they were not of the same version. In short we had mismatching dll’s duplication.

Of course, like always, after I fix a problem everything seems so obvious and I cant figure why I didn’t understand it much earlier. but anyway after 2 more minutes we had that one thing solved and we actually were ready to do some serious work. At that point however we ran out of time so we scheduled to continue another time.

Duplications are Evil

Yes the DRY principle which wikipedia defines as :"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." applies to more than just code and code design. It applies to all parts of the system, in my case it can be restated by the common sense directive:

You shall only have a single copy of any 3rd party dll checked into your source control

Yes I feel stupid

So where else can DRY be applied?  What example do you have?



Want to adopt Agile and don’t know where to start?
click here to learn

Sunday, 17 June 2012

More Agile Myths

Marc Löffler in this post talks about some agile Myths. about a year ago I blogged about some agile misconceptions. Here are some to add to this list.

Agile = No Design

In an agile process you usually wont see a specific design phase. In fact scrum for example does not explicitly talk about design at all. This leads some people to think that in an agile process design is not done or is not deemed important. Well actually quite the opposite. Design is such an important part of software development that trying to box it into a specific time/phase in a process simply doesn’t work. When development software you need the flexibility to change/update/adopt your design as you learn more and more.that is why in agile circles we will usually talk about emergent design, or iterative design. the idea is to design more and more of the product as we learn more and more about the problem.

Agile = No Planning

It still puzzles me how people reaches this conclusion. Yes there is no one single long term plan that we follow. But just by looking one can clearly see that most of the structure you have when following an agile process is centered around planning. In scrum in all the ceremonies we do some sort of planning. In sprint planning its quite obvious we plan a sprint, in daily meeting we pan the next day, in demo we gather feedback in order to help plan the next sprint and in a retrospect we plan how to improve.

Agile = Small Teams

When I started out most of the time coming to large companies I heard them saying that while agile sounded nice it seems to be only appropriate for small teams mainly or those “crazy websites” projects. Funny enough I’m lately starting to hear (usually in small companies) that while agile is nice, its too much of a process and is too strict for what we need. its only good for bigger projects when you need a process to get going. It’s funny how the wheel turns.
In truth an agile process can be used in both situation, and the actual goal of the process is to find a balance after some trial an error of course. on one hand we want to give enough structure as to avoid complete chaos and on the other to still allow for the flexibility and agility which are so important to stay competitive in the software industry.

What other agile myths do you know? What is your experience with those myths? feel free to comment…

Want to adopt Agile and don’t know where to start?
click here to learn

Monday, 10 October 2011

Your code should Always be working

Source control branches is always a good topic to argue about. if you read any of my previous topic (or just know me a little) you are aware that personably I think those to be a complete waste of time and effort. My personal experience (which is validated against places I consult in) is that most usages of branches are covering some inherent process problems that best be solved instead of hidden. but that’s not what I want to  talk about.
what I do want to discuss is one of the main argument people raise for justifying their need to use source branches. and usually it goes like this:
yes we would love to work on one main trunk, we see the great value in that. However, not all programmer knows how to work their code without breaking the rest of the system. therefore we use branches to prevent the system from breaking during development of new features. and we integrate their work based on needs and stability.
Frankly I can relate to this. I can understand what is missing here. We need some good strategies for working on code without hurting system stability. so here are some options for you.
Invisible Coding
The first and most trivial technique is using build it (in the programming language) mechanism for disabling code. Yes something like the infamous #ifdef directive for C/C++ that exists in most (all) modren software languages. The main idea here is that all new additions to the code are marked as disabled until they are ready be activated and integrated into the main system.
For most this would seem as an ugly patching/hacking and most programmers has a a natural dislike of such an option. and probably with a good reason. After all if the code is not active what is the big difference than just using a separate branch? well not much, the only real benefit in this is that at least one side of the integration is always done. when you are working on a new feature and still work on the main trunk, even if your new code is disabled, it is always updated with other changes being done to the system. And since in most cases enabling/disabling the new parts is quote easy. With just a little care you can do parts of the second side of the integration in an ongoing fashion making the final integration easier, safer and faster.
Decoupling of New Code
The second strategy takes the “invisible code” approach one step further. the main idea here is to write the new code into the main system, but this code will be decoupled from the main code in such a way that it will be easy to prevent actual usage of the new code until it is ready. Its like building a new part beside the main system and only connecting it when it is good and ready. technically speaking it’s a little harder to achieve and sometime require a little bit of juggling and some getting used to thinking this way. On the upside this make sure that all new code is integrated into the system in such a way that only the final steps of the integration (making sure everything works) is left for the end. the back and forth tedious merging is done along the way. Also, from my experience most developers find this approach natural and tend to work like this anyway when adding new stuff. However, the down side, is that in many cases the harder part is to actually to the connecting of the new parts into the existing system. sometime you find that you missed some staff that invalidate part/most/all you work done in isolation. I usually advice people trying to go this way to start by first  solving the connecting part. that is start by making the system integrate into a “dummy” new part making all the calls do nothing. and when that’s ready go over and fill in the missing parts.
Work Small
This is kind of a process work around. it has nothing to do with how to write code. The main idea is to always work on small features. so small that in fact they can be started and finished in a couple of days  making the use of a branch just a big overhead with no actual need. If you can start and finish in a matter of days, you can just work on your local copy focusing the actual code changes in a very short, delivering everything at the end. Actually this is just like branching but since it is for such a short period of time integration will not be an issue and most likely merging will not be required.
actually this strategy has all sorts of benefit outside the technical domain so it is a recommended idea no matter what else you do, and if/when needed it can also be combined with other strategies
Test Automation
Well this is probably the one thing that will make your code work at all time. if you have a good suite of automated tests that does a decent job at covering your system, the rest just falls into place. You just work on the main trunk and make sure that everything continue to function by running the tests after each change and before delivering. If you broke anything the tests will let you know, and you can just find another way of doing this. Of course having such a suite is something that sadly most people are short on. and those that do have are usually already solved this problem a long time ago. but lets face it you do need test automation no matter how you work.
The Mikado Method (The Missing Link)
That’s one is new for me, while I have encountered this over a year ago, only recently I managed to actually dive deep and read the book (an excellent one BTW, which can be downloaded here (for now)).
and for me that was the missing piece in the puzzle, the main idea of the Mikado method is turning the problem upside down. you start by stating you goal, you find out what are the prerequisites for achieving you goal, you apply them to your system, see what breaks, find what’s need to be done to complete the prerequisites, writ it down in a graph and then revert your system back. then we repeat the process for each derived prerequisite and continue to so until we find actual things that can be done without breaking the system. This is a very short and probably not so good description of the Mikado process. but the book does a great job at that so just go ahead and read the first two chapters to get you going.
The great thing about this method is that it uses the power of a source control system, in way that allow a programmer to chart his way until he maps all/most of the things to do in order to reach the Goal, and only then actual work on the code is started. This allow one to start working in small steps from the end to the start while keeping the system intact all the way. at the end this is just taking the “Work Small”  strategy and applying it to the “technical” side, resulting in breaking down the work into small technical steps that can be safely taken. and the best part is that this is an actual technical technique that can be practiced and mastered.

This are the strategy I have used and will use and for me those things work. I’m sure most of the things stated here works well in combined together and the trick is to use the right tool for the task. would love to hear about more techniques for handling the same situation.

Wednesday, 20 July 2011

So how are design pattern working for you?

A confession. I never did manage to make design pattern work for me.

A disclaimer. I don’t think that this is because design patterns are in any way “wrong” or “bad”.

Yes, I do use them occasionally and Yes, I do know a fair share of them. However, I always have this nagging feeling that I should know more patterns, and at the end of the day, when I’m actually designing my systems I rarely go:

“ahmm I can use the XXXX pattern to do this”.

So why is this so? why after so many years of using design patterns talking about patterns and even arguing quite a lot about them, I still can’t make them work for me?

I wonder…

The human brain as a pattern matching machine

Start of July I attended at Vipul Kocher session during the SIGIST conference, in his session Vipul talked quite a lot about patterns and specifically about testing patterns. All and all it was a very interesting session, out of which I would like to repeat two main idea’s. First, Vipul initial claim was that our brain is basically a very sophisticated and efficient pattern matching machine. We use patterns on a daily basis. We see patterns everywhere, we recognize all kind of patterns we create new pattern, and often enough we even use Meta patterns (patterns which are used to create new patterns). No wonder our brain is such effective in matching patterns.

Learning to speak

Vipul’s second idea I would like to quote, is the fact that human apply this pattern matching ability in or language learning process.

And in the first time we are not even aware we are doing so.

When learning our native tongue, our brains learns patterns for matching single words, to match complete sentences, to match grammars rule and to match common mistakes. And it does so without us being conscious to the process.

The second time we learn a language the process is different, instead of absorbing the patterns instinctively, we apply a conscious learning technique.Instead of understanding specific word, we translate meaning from our native tongue, instead of deducting the grammar we LEARN grammars rules from books (or a teacher). This is also a way of learning. However in general the end result is inferior, usage of our native tongue will always remain easier and will always be of higher quality.

Misplaced Design Patterns

When talking about design patterns there are a couple of anti pattern I see in their usage. Again, I don’t claim there is something inherently wrong with patterns. I do see however problems with their usage. The most common issue I see, is a problem in applying patterns. Specifically, too often I see misplaced design patterns scattered around systems. Look at your current system you are developing. How many singletons do you see there? are all of them necessary? how many times you have argues with someone that while XXX is a great pattern, using it here seem to be out of place?

Initially I thought that this is caused by simple lack of pattern knowledge and understanding. However I think the reason is simpler than that. Our brain is always on the look for patterns, our thought process is rigged to order the world around us into known patterns and shapes. It does so instinctively all the time, and specifically during design it tricks us to see patterns which actually might not be there. It takes a really trained eye and conscious effort to compensate. Failure in doing so results in having a misplaced pattern in our system.

Design Pattern as a language

Haim describe in “Design Patterns and the Tower of Babel” one very important benefit of using patterns. Patterns serve as a common design language for us, and this is good.

However there is a catch. At least for me, the Design Pattern language is our second language. As a second language I will always find it harder to use. When using a secondary language (as in English ), I always struggle for the right words (patterns), I fail to understand the nuances behind them, I make stupid grammar mistakes and occasionally I use inappropriate words (if you don’t believe me read this article again). When I use Design pattern I feel the same, no matter how much effort I invested and will invest in learning patterns, I think that for me the cause is lost. I will not be able to use design pattern as my “native design tongue

So what should we do?

I see two options, the first is making sure that pattern does become the native tongue for new comers to our profession. On the upside design patterns has got a hold and I do see this more and more new comers learn them very early. However,I think that this process is going too slow. In order to actually see this done on a bigger scale, design pattern should be embedded into basic training and should be thought at universities (which I haven’t seen happening yet)

The second option is for people like me, those that will always have a different native “design tongue”. Like always, the first step is to admit that we have a problem. The problem is that the pattern language will always feel uncomfortable and be less effective for us. We still can and should use it, but when we do, we should be aware that we are “translating” and in the process our meaning can get twisted.

This is very frustrating. Especially when a “native pattern speaker“ meet a “second langue pattern speaker” like me. No matter how I try to avoid it, I end up reverting to my native language in order to “keep up” and when I do confusion start to hit (resulting occasionally in some heated arguments). Therefore the second step is to always keep in mind and be aware that this is happening.

When two “Foreign pattern speakers” meet

And last, and this is what I should always remember to verify, sometime on the other side there is another “pattern as a second language“ kind of guy. When this happen to be the case, we can sometime, just maybe, skip the whole pattern things. Chances are that it will be easier to communicate using our native design tongue.

So what are you?

  1. a native design pattern speaker?
  2. learnt design pattern as your second language?

Thursday, 27 May 2010

Design is contextual

i once wrote about the fact that there is no perfect and absolute design approach/strategy. To me design always depends upon the context of the system it is developed for and it should evolve along with the system.

Furthermore, I believe design decision should also be based on the context of the people involved i.e. the development team. Meaning that a good design for a given system in one team might not be appropriate for a different team working on the SAME system

To understand the previous statement, we need to first consider the main goal in software design. Not what makes good design but what we would expect a good design to do for us, or why is design important. For me a good system design is one that will minimize both the system maintenance cost and the cost of of developing new capabilities. And if we can agree on this definition I would assert that it is only natural that the people working on the system must be considered in any design decision. Some people find that a high level of abstraction easy to work with, but other people prefer a more procedural approach and find the same level of abstraction hard to understand. Even when I consider myself I know that during different phases of my professional life my taste about design have changed and what I found to work for me these days does not looks resemble what i found easy to understand a few years ago. (and only part of this can be attributed to better design capabilities)

When choosing a design always balance your decisions between your design capabilities and the need to apply good design principles. Sometime going one way because someone smart said it should be like this (even if that person is really smart) will not benefit you unless you understand why this is good.

At the end no matter where you will go you will need to evolve the design along with the product and along with the team applying and using that design.

Wednesday, 14 April 2010

Don't be a Smart Ass Coder - Exercise in Rafctoring

Here's a piece of code I saw the other day.

the code is for real and given after massive renaming to protect the guilty

for ( int j = 0; j < 2; j ++ )
{
if ( j == 0 )
pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartAHandle());
else
pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartBAHandle());

if ( pObject )
{
ObjectGeometry objectGeometry =
pObject->GetGeometry();

for ( UINT i = 0;
i < objectGeometry.NumRectangles();
i ++)
{
Rectangle* pRect =
Repository::GetInstance()
->GetRectanglesByHandle(
pObject->GetRectnagleHandle(i, 0));
if ( pRect )
m_Repository.DiscardRect(
pRect->GetHandle()
);
}
m_Repository.DiscardSpread(
pObject->GetHandle());
}
}

First reaction was WTF !@$^@%@%^

Second reaction was common your not serious

after thing really sunk in, it was "Smart Ass"

Don't be a Smart Ass coder

Really don't! showing how smart you are through code serve no other purpose other then boosting your own ego. the immediate effect however is that it takes just a bit longer for other people to read your code. Yes you probably can deal with that, but show some respect to other people time. why do you make me read such a thing. cant this be made simpler?

of course it can, lets do that:

Step 1

the chunk of the method in fact clear some stuff in pObject, lets state that:

for ( int j = 0; j < 2; j ++ )
{
if ( j == 0 )
pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartAHandle());
else
pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartBAHandle());

CleanObject(pObject);
}
void CleanObject(Object pObject)
{
if ( pObject )
{
ObjectGeometry objectGeometry =
pObject->GetGeometry();

for ( UINT i = 0;
i < objectGeometry.NumRectangles();
i ++)
{
Rectangle* pRect =
Repository::GetInstance()
->GetRectanglesByHandle(
pObject->GetRectnagleHandle(i, 0));
if ( pRect )
m_Repository.DiscardRect(
pRect->GetHandle()
);
}
m_Repository.DiscardSpread(
pObject->GetHandle());
}
}

Step 2

do we really need a for loop with this weird if statement? Not really, in fact using the loop index for branching is probably a code smell.

Also who loop until 2?

use the oldest counting scheme (1, 2, many) and only when reaching many use a for.

so getting rid of that we get to:

pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartAHandle());
CleanObject(pObject);

pObject = Repository::GetInstance()
->GetObjectByHandle(
pParent->GetPartBAHandle());
CleanObject(pObject);

Step 3

The resulting CleanObject is doing two things:

  1. Clean all the rectangles inside object.
  2. Clean up the object itself.

Let separate those:

void CleanObject(Object pObject)
{
if ( pObject )
{
CleanRectnagles(pObject);

m_Repository.DiscardObject(
pObject->GetHandle());
}
}

void CleanRectnagles(Object &pObject)
{
ObjectGeometry objectGeometry =
pObject->GetGeometry();

for ( UINT i = 0;
i < objectGeometry.NumRectangles();
i ++)
{
Rectangle* pRect =
Repository::GetInstance()
->GetRectanglesByHandle(
pObject->GetRectnagleHandle(i, 0));
if ( pRect )
m_Repository.DiscardRect(
pRect->GetHandle()
);
}
}

Step 4

For good measure lets simplify CleanRectnagles even further:

void CleanRectnagles(Object &pObject)
{
ObjectGeometry objectGeometry =
pObject->GetGeometry();

for ( UINT i = 0;
i < objectGeometry.NumRectangles();
i ++)
{
CleanRectnaglesExtracted(pObject, i);
}
}

void CleanRectnagle(Object &pObject, UINT &rectIndex)
{
Rectangle* pRect =
Repository::GetInstance()
->GetRectanglesByHandle(
pObject->GetRectnagleHandle(rectIndex, 0));
if ( pRect )
m_Repository.DiscardRect(
pRect->GetHandle()
);
}

Final Result

and we end up at:

pObject = Repository::GetInstance()
->GetObjectByHandle(pParent->GetPartAHandle());
CleanObject(pObject);

pObject = Repository::GetInstance()->
GetObjectByHandle(pParent->GetPartBAHandle());
CleanObject(pObject);

void CleanObject(Object pObject)
{
if ( pObject )
{
CleanRectnagles(pObject);
m_Repository.DiscardObject(
pObject->GetHandle() );
}
}

void CleanRectnagles(Object &pObject)
{
ObjectGeometry objectGeometry =
pObject->GetGeometry();
for ( UINT i = 0;
i < objectGeometry.NumRectangles();
i ++)
{
CleanRectnaglesExtracted(pObject, i);
}
}

void CleanRectnagle(Object &pObject,
UINT &rectIndex)
{
Rectangle* pRect =
Repository::GetInstance()->
GetRectanglesByHandle(
pObject->GetRectnagleHandle(
rectIndex, 0));
if ( pRect )
m_Repository.DiscardRect(
pRect->GetHandle() );
}

Food For Thought

It still doesn't look clean enough. Looking closely one can easily spot misplaced operations. CleanRectnagles really looks like it belongs to Object class. The same holds true for CleanObject and CleanRectnagle. Was that so obvious in the original code?

CleanRectnagle can use an additional simplification, resulting in a clean method which belongs to the rectangle class.

etc, etc...

Summary

Take a look back at the initial piece of code, yes its a little shorter then the resulting code. However how long would it take you to understand it?

Remember when writing code the goal is not to show how smart you are the goal is to write simple straight forward code which is easily understandable all programmers reading it later.

Sunday, 15 November 2009

Is Typemock Isolator Evil - Round N+1

Every few months the argument for and against the advance abilities of the Isolator mocking framework burst again. This time it started with this post: Test driven design – Willed vs. Forced Designs

Disclaimer: I used to work for Typemock company and was in charge for a long time over the development of the framework. so I claim no kind of objectivity .

the argument for and against usually circle around the following:

on one side, people claim that Isolator "breaks" the language barriers and, by allowing any kind of design to be implemented will end up in helping to build a poorly designed system.

on the other side, by allowing the freedom to design at will Isolator shift the responsibility back to the developer allowing him to choose the "best" design as he sees fit.

here are some points I want to comment on:

If you need Isolator you have a bad design

Actually that one is in most cases true. However the following claim "you have bad design" also holds for too many cases as well. Yes I'm saying that most systems out there are poorly designed. I'm also saying that most software project out there will fail. What I don't like about the initial claim is the conclusion that usually follows:

If you need isolator when you have poor design, usage of isolator will end up with a poor design.

That statement is plain wrong, you will end up with poor design unless you learn how to design better. The effect Isolator (or any tool for that matter) will have on a team design skills is minimal at best. Pragmatically speaking if you are are working on a legacy system isolator is probably the better choice no matter what. If you are working on a newly project and you just start out TDD, most likely using isolator will increase the chances you'll be able to stick with it. (adding the need to relearn design at this stage is soo much harder), and if you're working on a new project and you do know how to TDD. Then you should just know better and be able to safely use the tool. If you don't then you really do have a problem.

Isolator breaks the natural barriers of the language

Yes it does, but the statement "Statics are the death of testability" which actually means "don't use static methods" adds barriers to the language which is not there. so what's the better approach? again I don't know. It really depends on your personal preferences and has nothing to do with what is the best design

Actually there's no such thing is the best design. Every design must evolve always to fit the system needs.

Show me a concrete example

example number 1:

many systems have a dependency on the time of day. the naive way to approach that is to use DateTime.Now. but oops that one cant be faked (its a static method) making it a real pain to test. so experienced programmer introduce the ITime interface wrapping the system time with an interface and then adding some concrete code to make it work, all for the sake of testability. here's an example taken from the testify project on how to implement this:

public static class SystemClock {

private static DateTime? fixedTime;

public static DateTime Now {
get {
if (fixedTime.HasValue)
return fixedTime.Value;
return DateTime.Now;
}
}

internal static void Set(DateTime value) {
fixedTime = value;
}

internal static void Reset() {
fixedTime = null;
}
}
Please enlighten me as why this is better/simpler as opposed to use of DateTime.Now.


example number 2:

I have a class A depends on Class B. Class B is the ONLY concrete class implementing the interface ISomeInterafce (and most likely this will hold true forever). Class A is the only place (for now and most likely forever) ISomeInterface is used. yes this is a simple example but since I'm inventing it, I get to set the rules.

and there are several ways to approach this:

1. Use some IOC container to instantiate B and send it to A. a valid OO way with many benefits however in my concrete example (and yes I'm the one setting the rules). I don't have a true need for a full pledged IOC yet, and this very simple scenario wont be the one causing me to start using an such a big hammer

2. Use a factory - a simpler version of the IOC container idea, much more light weight. but still at this point of time (and yes I get to make the rules) under the specified circumstance it falls under the YAGNI directive. If the situation changes (i.e. more places will use ISomeInterafce or more "kinds" of ISomeInterafce will evolve) a factory will be used but for now I don't really need that.

3. Instantiate B somewhere and pass it into A (the simplest form of DI) - a very simple solution which is valid under this scenario. the down side for it are , that it exposes some inner working details of A which may not be a good idea AND most likely it only shifts the problem to someplace else.

4. Just use a new statement somewhere inside A (lets say constructor) - I like this way. Its the simplest thing that can possibly work, and I'm not tied to the "design for testability" chains, so I can do that. and just before I get chopped, yes taken outside this context of this simple concrete example is most likely not a good strategy.



I want to make the Choices. I'm the professional trained to do them. I wont stand being TOLD how to do my job, not by a person, and especially not by a tool.

Friday, 11 September 2009

YAGNI - It all Connects

connection Everything in software connects. Here a common thread that connects the following agile? principles:

YAGNI - You Aint Gonna Need It.

YAGNI is referred to the fact that most time in software development its useless to try and think ahead since most of the time we just don't really know if we are going to need this or not. as Ron Jeffries puts it:

"Always implement things when you actually need them, never when you just foresee that you need them."

KISS - Keep It Simple (Stupid)

Which is the same as saying do "The simplest thing that could possibly work" we use this phrase when we want to emphasize that simplicity in software has usually much more value than we initially think.

There is no one perfect design

I'm not sure this has anything specific to agile. But this one has been gnawing at me for quite some time. Too many times I've been in design sessions were people were deeply arguing about whose design was the best, when clearly they were all good enough. While clearly there is such a thing as good and bad design. Mostly its a matter of context. Every good design is aimed at allowing a certain type of change to be easy. However by doing so, many times, it makes other types of changes harder.

So how do all these three connects?

If we accept the fact that there is no one perfect design and each design is best suited to a given type of change, and we also accept the fact that we lack the gift of vision, so in most times we fall into the YAGNI principle. We are left with the conclusion that we must do "The simplest thing that could possibly work". Even if at that point of time the resulting design doesn't look great. That's OK. If and when we will need to apply changes, then we will know exactly what type of change is required. And only then we shall evolve the design (by Refactoring) to cleanly accommodate that type of change (which is most likely to happen again)

(I would like to thank Uncle Bob, that in his talk about SOLID design in NDC has helped realize how these principles close the circle)

Wednesday, 3 June 2009

Evolving Design - Its a must!

A couple of days ago I read Gil's post about "Good Design Is Not Objective", in it he writes

So are there "good" or "bad" designs? Every person has an opinion. Opinions change over time. Problems and technologies change over time, and a design can help or interfere with the project, but you'll know that in hindsight.

Yesterday, at one of my client a simple question turned into a related discussion. One of the software architectures asked me if I ever saw (and what do I think of) a system which uses a global variable repository. One that every part of the system could use at will  to store data and is used as way of communicating between various parts of the system. Apparently that kind of an approach is used in their system and he wanted to know what I would say.

After thinking a little, I said that the only system which seems to me to be similar would be Windows registry, I said that I never encountered such a system in a project I was working on (at least not on the scale he was talking about). I also said that in my past each time I used such global variable (in a similar manner) I regretted it. And last that it really sounds like very "old fashion" approach to design. Something that kind of contradicts object oriented design.

The guy told me he said, that this part in question is very old and was written some 15 years ago when the company was at its startup stage. It appears that the entire system was evolved on top of it, which made it very hard to replace. in fact the cost was so high that each time someone considered it they decided to leave it as is.

Now I think this is a very interesting case that demonstrates how our continual search for the Best Design is just stupid.

There is no such thing as the Best Design!

Like most things, design also carries a context. In this case the current mechanism they have was (as the guy admitted) the quickest and cheapest way of reaching a product (one which people will buy). At that time (15 years ago) the technology (they were writing in C) and software engineering approaches were in line with such a mechanism. And it was a reasonable design at that point of time.

Is it still so today? absolutely not!

The company is no longer a startup, what was good at that time is really bad today. The needs has changed over time, the technology has changed over time, and the product has changed over time.

As Gil said it:

Time Changes everything

The Best Design today will probably wont be the Best Design tomorrow. A developer accepting that fact, can focus on producing a "good enough" design and evolving it as needed over time.

In my opinion that was the actual Mistake done. Its not that the design was wrong. its the fact that they assumed it wont need to change. That assumption made the cost of actually changing it high resulting in an unsuitable design they have today.

Thursday, 2 October 2008

Decoupling Testing from Design

A recent discussion has recently sparked up about whether or not can testing practices can be decoupled from design practices. Roy in his latest post "Unit Testing decoupled from Design == Adoption", has argued that one of the factor which prevents the masses from adopt AUT is the strong perception that AUT and design are strongly coupled, a perception which in his opinion is wrong. Udi on the other hand argues in "Unit Testing for Developers and Managers" that testing practices and design goes hand in hand.

So can Testing be decoupled from Design?
Well my answer is: Yes but probably not.

The Context

To clarify this cryptic answer I first need to put those practices in a context. As I see it, both design and testing are just means to reach an end. The ultimate goal is producing class A quality software. Software which brings real business value to its user/Customer. Most customers are completely indifferent to the system internal design, and are usually not that interested in how it was tested. They just wants a working reliable system which answer their needs.

Decoupling Testing from Design

As Roy I also believe that from a practical sense design and testing can be done independently. Too often have I heard managers and programmers alike claiming that they cant adopt AUT/TDD because that will lead to a major system rewrite(oops I meant redesign) and currently there is no time for that. This argument is just plain wrong (in today's world). Using the proper toolset the need to redesign the system can be decoupled from the technical problem of writing unit tests.

So My answer is yes one can decouple the technical need for redesign from the ability to write unit tests.

Testing and Design Correlation

However putting Design and Testing in the above context leads me to believe that both are just ways to achieve quality in a software system. In that aspect they cant be truly decoupled. Its like trying to decouple reading&writing skills from basic math skills, technically they can be decoupled but at the end if you want to get somewhere, you'll need to learn them both. No matter how hard that might be.

In fact My experience has shown me that both practices are mutually beneficial. Its easier and safer to redesign a system when you have a comprehensive set of tests as a safety net, and its much easier to write effective unit tests on a well designed system. Still one can redesign a system without automated tests (that how most people are doing it) and I have yet to see a system no matter had bad its design that wouldn't have a strong ROI for adding some test automaton.

TDD

However many times in this discussion I get the feeling that we are missing the real essence here, and the essence is the message that TDD approach brings. I have always felt (like many other) that TDD true innovation lies in its being a design practice. Unit testing and automation concepts were here long before the TDD, but only recently these practices took hold. In fact today trying to separate them in a discussion is well, kind of pointless. Too often I referred to AUT and people heard and understood TDD. There is something more to TDD then just writing

I think that Michael has captured the essence of TDD in his post: "The Flawed Theory Behind Unit Testing":

Unit testing does not improve quality just by catching errors at the unit level. And, integration testing does not improve quality just by catching errors at the integration level. The truth is more subtle than that. Quality is a function of thought and reflection - precise thought and reflection. That’s the magic. Techniques which reinforce that discipline invariably increase quality.

And that's how TD captures me, what makes TDD tick for me his the strong coupling between design and testing that it brings into my daily process. For me doing TDD is not just about writing unit tests. TDD is about investing time in thinking how the system should look writing tests to reflect those thoughts and refactoring the code to make it so.

so at the end follow Ian advise:

Make it work, then make it right.

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Walgreens Printable Coupons