From: Daniel T. on
AndyW <a(a)b.no.email> wrote:
> "Daniel T." <daniel_t(a)earthlink.net> wrote:
> > Robert Martin <unclebob(a)objectmentor.com> wrote:
> >
> > > Bad coded is always more expensive than clean code; and so is
> > > always the loser. Until we all accept this, our profession will
> > > never climb out of the hacker status it currently has.
> >
> > I'm not going to go so far as to make an assertion of my own. But
> > I certainly don't accept yours. "Good code" is *always* cheaper
> > than "bad code"? I don't see where that statement holds any
> > validity, unless a bunch of assumptions are made.
>
> I would probably suggest that the code that takes the least amount
> of time out of the teams production and maintenance schedule over
> the long run is probably going to be cheaper than the code that
> requires more time be used to develop and maintain it over the same
> period of time.
>
> But it would be an idea to cost out one person doing a 40 hour week
> of development on a clean code environment vs a dirty code
> environment and see what one thinks the difference is.

How about an example:

Some developers are working on the same code base and are independently
trying to do the same job. Let's say that job is to add a function that
works something like a function that already exists, but needs to change
in some way that is as yet undetermined.

Developer A, copies and pastes the existing function, then tests it,
modifying the function for tests that fail.

Developer B writes the new function from scratch without reference to
the existing function.

Developer C examines the existing function against the new context in an
effort to determine what is going to have to change, then modifies that
function so that it can be reused in the new context, then tests to make
sure it still works in the old context. Then he must test his generic
function the new context.
- - - - -

Developers A & B need make no changes to existing code to get the new
functionality into the system, thus their risk is lower (they are less
likely to break existing code if they don't change existing code.)

Developer A can start testing against a largely finished function almost
immediately. He has a reference to work with which is always faster than
attempting to create from first-principles (as B is doing.)

Developer C must first modify existing functionality (both the existing
function and probably the context in which it is currently being used,)
to create a more generic function that will fit in both contexts, then
test to see if his assumptions were correct.

Developer C has created "clean" code in my book, the others have created
"dirty" code. It seems to me though that A will have a function up and
running that passes the tests faster than the other two. He didn't have
to modify/retest existing code like C did, and he didn't have to create
from first-principles like B did.

Ah, but now developer A and B have to clean their code! Well, they don't
have to, if this were a race to get the function done, they would
deliver at that moment because the tests pass. Their code is "dirty" but
they got done first (likely with A getting done before B.)
- - - - -

Let's look at the clean-up process anyway. Developers A & B will now
have to do what developer C did up front by refactoring the code.
Developer A has two functions that are as alike as they could possibly
be so it's just a matter of factoring out the like bits into a generic
function. Developer B has two functions that do largely the same thing,
but may do it in completely different ways, so he will probably find it
harder to refactor the code. Between the two of them, developer A is in
the better situation.

So if you include developer A's clean-up phase, the question comes down
to this: Can developer C design, up front, a better (i.e., more
reusable) function and then test and reuse it in both contexts faster
than developer A can copy-paste the existing function, modify it to fit
the new context then factor out the duplication. I submit that the
answer lies solely on the experience of developer C. If his up front
assumptions are correct, then he will win. Otherwise developer A will
win. However, in both cases the end code is "clean" so I'm not sure that
it is relevant to this discussion.
From: AndyW on
On Sat, 27 Jan 2007 16:55:55 GMT, "Daniel T." <daniel_t(a)earthlink.net>
wrote:

>AndyW <a(a)b.no.email> wrote:
>> "Daniel T." <daniel_t(a)earthlink.net> wrote:
>> > Robert Martin <unclebob(a)objectmentor.com> wrote:
>> >
>> > > Bad coded is always more expensive than clean code; and so is
>> > > always the loser. Until we all accept this, our profession will
>> > > never climb out of the hacker status it currently has.
>> >
>> > I'm not going to go so far as to make an assertion of my own. But
>> > I certainly don't accept yours. "Good code" is *always* cheaper
>> > than "bad code"? I don't see where that statement holds any
>> > validity, unless a bunch of assumptions are made.
>>
>> I would probably suggest that the code that takes the least amount
>> of time out of the teams production and maintenance schedule over
>> the long run is probably going to be cheaper than the code that
>> requires more time be used to develop and maintain it over the same
>> period of time.
>>
>> But it would be an idea to cost out one person doing a 40 hour week
>> of development on a clean code environment vs a dirty code
>> environment and see what one thinks the difference is.
>
>How about an example:
>
>Some developers are working on the same code base and are independently
>trying to do the same job. Let's say that job is to add a function that
>works something like a function that already exists, but needs to change
>in some way that is as yet undetermined.
>
>Developer A, copies and pastes the existing function, then tests it,
>modifying the function for tests that fail.
>
>Developer B writes the new function from scratch without reference to
>the existing function.
>
>Developer C examines the existing function against the new context in an
>effort to determine what is going to have to change, then modifies that
>function so that it can be reused in the new context, then tests to make
>sure it still works in the old context. Then he must test his generic
>function the new context.
>- - - - -
>
>Developers A & B need make no changes to existing code to get the new
>functionality into the system, thus their risk is lower (they are less
>likely to break existing code if they don't change existing code.)
>
>Developer A can start testing against a largely finished function almost
>immediately. He has a reference to work with which is always faster than
>attempting to create from first-principles (as B is doing.)
>
>Developer C must first modify existing functionality (both the existing
>function and probably the context in which it is currently being used,)
>to create a more generic function that will fit in both contexts, then
>test to see if his assumptions were correct.
>
>Developer C has created "clean" code in my book, the others have created
>"dirty" code. It seems to me though that A will have a function up and
>running that passes the tests faster than the other two. He didn't have
>to modify/retest existing code like C did, and he didn't have to create
>from first-principles like B did.
>
>Ah, but now developer A and B have to clean their code! Well, they don't
>have to, if this were a race to get the function done, they would
>deliver at that moment because the tests pass. Their code is "dirty" but
>they got done first (likely with A getting done before B.)
>- - - - -
>
>Let's look at the clean-up process anyway. Developers A & B will now
>have to do what developer C did up front by refactoring the code.
>Developer A has two functions that are as alike as they could possibly
>be so it's just a matter of factoring out the like bits into a generic
>function. Developer B has two functions that do largely the same thing,
>but may do it in completely different ways, so he will probably find it
>harder to refactor the code. Between the two of them, developer A is in
>the better situation.
>
>So if you include developer A's clean-up phase, the question comes down
>to this: Can developer C design, up front, a better (i.e., more
>reusable) function and then test and reuse it in both contexts faster
>than developer A can copy-paste the existing function, modify it to fit
>the new context then factor out the duplication. I submit that the
>answer lies solely on the experience of developer C. If his up front
>assumptions are correct, then he will win. Otherwise developer A will
>win. However, in both cases the end code is "clean" so I'm not sure that
>it is relevant to this discussion.

They are valid examples, but I would suggest that you actually cost it
out as an exercise (on an person/hour basis). The numbers actually
make the process clearer without the ambiguity of the words (not that
I found the above ambiguous).

The main thing that it appears to me that you have skirted (left out)
is that of risk. It seemed from reading the example that there are
risks inherant in each example, but you didn't cost them out (factor
them in). When you do the costing over the long run, thats were I
suspect you will see the impact of each process.

Without the factoring of risk, nor of that of cost its implying to me
that there is no software improvement process inherent in any of the
above process. It shouldnt be up to the experience of developer C on
how successful a process is, it [the success] should be a known
quanitity which a mature development environment will be able to
caclulate (in my opinion).

Andy

From: Daniel T. on
AndyW <a(a)b.no.email> wrote:
> "Daniel T." <daniel_t(a)earthlink.net> wrote:

> > How about an example:
> >
> > Some developers are working on the same code base and are
> > independently trying to do the same job. Let's say that job is to
> > add a function that works something like a function that already
> > exists, but needs to change in some way that is as yet
> > undetermined.
> >
> > Developer A, copies and pastes the existing function, then tests
> > it, modifying the function for tests that fail.
> >
> > Developer B writes the new function from scratch without reference
> > to the existing function.
> >
> > Developer C examines the existing function against the new context
> > in an effort to determine what is going to have to change, then
> > modifies that function so that it can be reused in the new
> > context, then tests to make sure it still works in the old
> > context. Then he must test his generic function the new context.
> > - - - - -
> >
> > Developers A & B need make no changes to existing code to get the
> > new functionality into the system, thus their risk is lower (they
> > are less likely to break existing code if they don't change
> > existing code.)
> >
> > Developer A can start testing against a largely finished function
> > almost immediately. He has a reference to work with which is
> > always faster than attempting to create from first-principles (as
> > B is doing.)
> >
> > Developer C must first modify existing functionality (both the
> > existing function and probably the context in which it is
> > currently being used,) to create a more generic function that will
> > fit in both contexts, then test to see if his assumptions were
> > correct.
> >
> > Developer C has created "clean" code in my book, the others have
> > created "dirty" code. It seems to me though that A will have a
> > function up and running that passes the tests faster than the
> > other two. He didn't have to modify/retest existing code like C
> > did, and he didn't have to create from first-principles like B
> > did.
> >
> > Ah, but now developer A and B have to clean their code! Well, they
> > don't have to, if this were a race to get the function done, they
> > would deliver at that moment because the tests pass. Their code is
> > "dirty" but they got done first (likely with A getting done before
> > B.)
> > - - - - -
> >
> > Let's look at the clean-up process anyway. Developers A & B will
> > now have to do what developer C did up front by refactoring the
> > code. Developer A has two functions that are as alike as they
> > could possibly be so it's just a matter of factoring out the like
> > bits into a generic function. Developer B has two functions that
> > do largely the same thing, but may do it in completely different
> > ways, so he will probably find it harder to refactor the code.
> > Between the two of them, developer A is in the better situation.
> >
> > So if you include developer A's clean-up phase, the question comes
> > down to this: Can developer C design, up front, a better (i.e.,
> > more reusable) function and then test and reuse it in both
> > contexts faster than developer A can copy-paste the existing
> > function, modify it to fit the new context then factor out the
> > duplication. I submit that the answer lies solely on the
> > experience of developer C. If his up front assumptions are
> > correct, then he will win. Otherwise developer A will win.
> > However, in both cases the end code is "clean" so I'm not sure
> > that it is relevant to this discussion.
>
> They are valid examples, but I would suggest that you actually cost
> it out as an exercise (on an person/hour basis). The numbers
> actually make the process clearer without the ambiguity of the words
> (not that I found the above ambiguous).

The Mythical Person Hour?

> The main thing that it appears to me that you have skirted (left
> out) is that of risk. It seemed from reading the example that there
> are risks inherant in each example, but you didn't cost them out
> (factor them in). When you do the costing over the long run, thats
> were I suspect you will see the impact of each process.

I specifically mentioned risk in the example, so I'm not sure what you
mean here. Person C is modifying working code without a clear, testable,
goal. Whether or not such a strategy is effective will depend
exclusively on how well he understands the problem.

> Without the factoring of risk, nor of that of cost its implying to
> me that there is no software improvement process inherent in any of
> the above process. It shouldnt be up to the experience of developer
> C on how successful a process is, it [the success] should be a known
> quanitity which a mature development environment will be able to
> caclulate (in my opinion).

This sounds like you are expecting developers to be plug-in replaceable.
Can a football coach develop plays that ignore the particular skill sets
of the players he is working with? Of course not. Nor can a lead
software engineer develop effective development strategies in total
ignorance of the skill set of the employees he will be working with. We
aren't on an assembly line after all.
From: Robert Martin on
On 2007-01-27 10:55:55 -0600, "Daniel T." <daniel_t(a)earthlink.net> said:

> AndyW <a(a)b.no.email> wrote:
>> "Daniel T." <daniel_t(a)earthlink.net> wrote:
>>> Robert Martin <unclebob(a)objectmentor.com> wrote:
>>>
>>>> Bad coded is always more expensive than clean code; and so is
>>>> always the loser. Until we all accept this, our profession will
>>>> never climb out of the hacker status it currently has.
>>>
>>> I'm not going to go so far as to make an assertion of my own. But
>>> I certainly don't accept yours. "Good code" is *always* cheaper
>>> than "bad code"? I don't see where that statement holds any
>>> validity, unless a bunch of assumptions are made.
>>
>> I would probably suggest that the code that takes the least amount
>> of time out of the teams production and maintenance schedule over
>> the long run is probably going to be cheaper than the code that
>> requires more time be used to develop and maintain it over the same
>> period of time.
>>
>> But it would be an idea to cost out one person doing a 40 hour week
>> of development on a clean code environment vs a dirty code
>> environment and see what one thinks the difference is.
>
> How about an example:
>
> Some developers are working on the same code base and are independently
> trying to do the same job. Let's say that job is to add a function that
> works something like a function that already exists, but needs to
> change in some way that is as yet undetermined.
>
> Developer A, copies and pastes the existing function, then tests it,
> modifying the function for tests that fail.
>
> Developer B writes the new function from scratch without reference to
> the existing function.
>
> Developer C examines the existing function against the new context in
> an effort to determine what is going to have to change, then modifies
> that function so that it can be reused in the new context, then tests
> to make sure it still works in the old context. Then he must test his
> generic function the new context.
> - - - - -
>
> Developers A & B need make no changes to existing code to get the new
> functionality into the system, thus their risk is lower (they are less
> likely to break existing code if they don't change existing code.)
>
> Developer A can start testing against a largely finished function
> almost immediately. He has a reference to work with which is always
> faster than attempting to create from first-principles (as B is doing.)

Unfortunately this logic is compelling. Yes, both A and B will get
their function working faster than C will. But the function is not
integrated into the system. To integrate it they are going to have to
modify one or more control flows in the existing software. They also
have to make sure that each of those control flows puts the system in a
state that is apropriate for their function. They'll also have to make
sure that the function leaves the system in a state that is appropriate
to *all* the incomming control flows.

If they rush this, they won't have put in the abstractions necessary to
test that the *system* works with the new function in place. Perhaps
they assumed that little could go wrong so they just wired the new
function in place and decided to test the new function manually. If
there are N control flows that lead to the new function, they will have
to run N manual tests. Each of those manual tests requires Xi second
of setup time. The total test time is large.

If they find a bug, they must repeat. If they find another they must
repeat. etc.

> Developer C must first modify existing functionality (both the existing
> function and probably the context in which it is currently being used,)
> to create a more generic function that will fit in both contexts, then
> test to see if his assumptions were correct.

Correct. C will strive to minimize the number of affected control
flows by making his solution generic. He does this by working one
control flow at a time and watching for similarities. He keeps each
control flow independently testable using automated test cases. He
builds the abstractions that keep the control flows isolated and
testable, and kees the function generic. When all his tests pass, he
is done. He will beat A and B.

Now let's take the case where there is only one affected control flow.
A and B must put one if statement into one place in the code once they
get their function working. C has to find a way to modify the existing
function to be generic. This could be as simple as the same if
statement, but in the function itself rather than in the affected
control flow. Or it could mean breaking the existing function up using
TemplateMethod or Strategy. In this case A and B MIGHT finish a bit
before C. MIGHT. Of course if anything goes wrong C will win because
C has the automated tests and the cleanest solution.

So, in the end, there are statistical anomalys which, from time to
time. allow the mess maker to finish before the clean coder. But they
are rare. And given any random sequence of activies the time spent by
the mess maker will almost always be longer than the time sent by the
clean coder.

Yes, it's possible that all the molecules in your laptop will, quite by
accident, find themselves all moving at exactly the same speed in
exactly the same direction, and your laptop will leap off the table and
hit the ceiling leaving behind a fog of condensed humidity as it's
temperature plumets to near absolute zero. But it's not very likely.
--
Robert C. Martin (Uncle Bob)��| email: unclebob(a)objectmentor.com
Object Mentor Inc.� � � � � ��| blog:��www.butunclebob.com
The Agile Transition Experts��| web:���www.objectmentor.com
800-338-6716� � � � � � � � ��|



From: Daniel T. on
Robert Martin <unclebob(a)objectmentor.com> wrote:
> "Daniel T." <daniel_t(a)earthlink.net> said:

> > Some developers are working on the same code base and are
> > independently trying to do the same job. Let's say that job is to
> > add a function that works something like a function that already
> > exists, but needs to change in some way that is as yet
> > undetermined.
> >
> > Developer A, copies and pastes the existing function, then tests
> > it, modifying the function for tests that fail.
> >
> > Developer B writes the new function from scratch without reference
> > to the existing function.
> >
> > Developer C examines the existing function against the new context
> > in an effort to determine what is going to have to change, then
> > modifies that function so that it can be reused in the new
> > context, then tests to make sure it still works in the old
> > context. Then he must test his generic function the new context. -
> > - - - -
> >
> > Developers A & B need make no changes to existing code to get the
> > new functionality into the system, thus their risk is lower (they
> > are less likely to break existing code if they don't change
> > existing code.)
> >
> > Developer A can start testing against a largely finished function
> > almost immediately. He has a reference to work with which is
> > always faster than attempting to create from first-principles (as
> > B is doing.)
>
> Unfortunately this logic is compelling. Yes, both A and B will get
> their function working faster than C will. But the function is not
> integrated into the system. To integrate it they are going to have
> to modify one or more control flows in the existing software. They
> also have to make sure that each of those control flows puts the
> system in a state that is apropriate for their function. They'll
> also have to make sure that the function leaves the system in a
> state that is appropriate to *all* the incomming control flows.
>
> If they rush this, they won't have put in the abstractions necessary
> to test that the *system* works with the new function in place.
> Perhaps they assumed that little could go wrong so they just wired
> the new function in place and decided to test the new function
> manually. If there are N control flows that lead to the new
> function, they will have to run N manual tests. Each of those manual
> tests requires Xi second of setup time. The total test time is
> large.
>
> If they find a bug, they must repeat. If they find another they must
> repeat. etc.

There is nothing in the example that requires A and B to test manually
or otherwise be undisciplined in their approach, hell they could be
running test first. If they are running test first, then after each test
is written, B and C will have to add/modify code to cause the test to
pass, while in many cases for A, the test will pass the first time.

> > Developer C must first modify existing functionality (both the
> > existing function and probably the context in which it is
> > currently being used,) to create a more generic function that will
> > fit in both contexts, then test to see if his assumptions were
> > correct.
>
> Correct. C will strive to minimize the number of affected control
> flows by making his solution generic. He does this by working one
> control flow at a time and watching for similarities. He keeps each
> control flow independently testable using automated test cases. He
> builds the abstractions that keep the control flows isolated and
> testable, and kees the function generic. When all his tests pass, he
> is done. He will beat A and B.
>
> Now let's take the case where there is only one affected control
> flow. A and B must put one if statement into one place in the code
> once they get their function working. C has to find a way to modify
> the existing function to be generic. This could be as simple as the
> same if statement, but in the function itself rather than in the
> affected control flow. Or it could mean breaking the existing
> function up using TemplateMethod or Strategy. In this case A and B
> MIGHT finish a bit before C. MIGHT. Of course if anything goes wrong
> C will win because C has the automated tests and the cleanest
> solution.

Again, you are assuming that A and B are undisciplined. They may in fact
be highly disciplined.

XP almost requires one to follow developer A's strategy. XP says "do the
simplest thing that could possibly work", well the simplest thing to get
that first test to pass would be to copy the existing function and paste
it in the new function. Then XP requires refactoring, which is exactly
what A does during his clean-up phase. Meanwhile, developer C is
engaging in small up front design. He is trying to factor code that
exists only in his head.

Unless C is above average, he will, in the processes of modifying the
existing function, break currently working tests, then he will have
backtrack and try a different idea. A and B will not break any existing
tests while adding their new functionality.

On top of that, once A has the new functionality added, he will have two
functions that look very much alike and a whole suite of passing tests.
Refactoring working code is easer than trying to create well factored
code up front.

> So, in the end, there are statistical anomalys which, from time to
> time. allow the mess maker to finish before the clean coder. But
> they are rare. And given any random sequence of activies the time
> spent by the mess maker will almost always be longer than the time
> sent by the clean coder.

Again, you are adding assumptions. There is no reason to suppose that
developer A and B are somehow inherently undisciplined. They are simply
following a different procedure to do the same job.

The key, to my mind, is that developer A, at all times in the processes,
has reference code to work with. While creating the new function he has
the old function as a reference (something B lacks) and while
integrating the two functions into one, he has both functions to work
with (something C lacks.) Unless the others are especially good at up
front design, A is in a better position to be done faster.

Now I will grant that if all the developers are highly experienced,
developer C will win (A and B are using training wheels when they don't
need them.) I will also grant that experienced developers will always
beat inexperienced developers no matter what method any of them use.

So, to my mind, one can't say categorically that small up front design
will always win out over copy-paste code, nor can one say the opposite.
It all depends on the skill/experience of the developer.