Re: Open question - leverage all features liberally, or be selective?
nospam@nospam.n ospam (Steve Jorgensen) wrote in
<esbcmvo1edtu16 7bol6o48o0p2vl0 esdif@4ax.com>:
[color=blue]
>On Mon, 15 Sep 2003 20:33:00 GMT, dXXXfenton@bway .net (David W.
>Fenton) wrote:
>
>...[color=green]
>>
>>These are my principles, which I think are in agreement with
>>yours, but you have different emphasis:
>>
>>1. code for the task at hand.
>>
>>2. code in a fashion that will require minimal change if the code
>>needs to be enhanced.
>>
>>We agree on that, but where we disagree is on how much work goes
>>into determining #2. I think you need to think carefully about
>>structure before you implement and make sure that you do as much
>>as you can to structure your code to make it independent of
>>future changes.
>>
>>And example from last week:
>>
>>I had hired somebody to do a little work for me and when I got
>>the results, he had followed my instructions, insofar as I'd been
>>clear, but he'd done it in a fashion that was not as flexible as
>>what I wanted. It involved creating a dialog form to collect the
>>required fields for adding a new record to a person table. My
>>approach to dialogs is that the dialog knows *nothing* about the
>>environment outside itself. Secondary to that is that the dialog
>>itself should be called from one piece of code only, so that the
>>only code that knows anything about the dialog is the code that
>>opens it and closes it (though a multi-purpose dialog may have
>>more than one calling code context).[/color]
>
>Well, I would argue that it's OK to do something simple that works
>for a single case, then extend it when (and if) the second case
>arises. . . .[/color]
What if you are pretty damned sure the second case will arise?
What if it doesn't take any more work to code for the second case
than it does to code for the first?
[color=blue]
> . . . When the second case comes along, I would approach it
>with the strategy of "Rape and paste, then refactor".
>Here, you simply cut and paste the code, form, etc., change what's
>different for the second case, then gradually refactor out
>duplication between the cases starting with the lowest hanging
>fruit (biggest chunks that are easiest to grab). When you're
>done, you have basically the goal you were describing above.[/color]
I think it's easier to choose an architecture that has no
unnecessary dependencies on the specifics of its initial
implementation.
In schema design, say you had an application where in the original
design, everyone was absolutely certain that there'd never be a
need for more than one address per person. So, you put the address
in the Person table, and then they decide they need a second
address, so then you move to a 1:N address table and restructure
the existing data accordingly.
If you'd put the address in a 1:1 table, though, you would have had
very little work to change the relationship to 1:N. You might think
that implementing the 1:1 address would require a more complex UI,
but it actually doesn't at all -- you just join the address table
in the recordsource of your person form and plop the fields on your
form. When you convert to 1:N, then you have to change the
recordsource to take out the join to the address table and create a
subform for the addresses and remove the existing address fields
from your Person form.
Do you do all the work preparing for the change on the front end?
ABSOLUTELY NOT.
But you choose a STRUCTURE that gives you maximum flexibility along
lines that are foreseeable at design time.
In terms of implementation, the 1:1 address table takes no more
time than putting the fields in the Person table. In terms of UI,
it is indistinguishab le to the users. But in terms of flexibility,
you save all that time restructuring existing data. Also, if you
got any lookup routines that use addresses, you don't have to
revise those in any significant way when you change to 1:N for the
addresses.
To me, it's a no-brainer -- you do the 1:1 table on the front just
in case you need 1:N later, and the *cost* of doing so is basically
nothing.
That's the kind of situation I'm talking about, where you have a
choice between two methods that take the same amount of time to
implement (more or less), but one of which allows more future
flexibility, *even if you end up never needing it*.
[color=blue]
>While refactoring, look for any functionality similar to something
>that exists elsewhere in the code, and use it if it's pluggable.
>If it's not pluggable, add a comment there, finish the current
>refactoring cycle, then go back to the comment and refactor again
>to remove duplication with the other code. Repeat until beauty
>arises.[/color]
If the basic structure is there already, you don't have to do
nearly as much reworking, as in the schema example above.
[color=blue][color=green]
>>Now, the problem with the code I got from this programmer was
>>that he had rightly separated out the opening of the form to
>>collect the information for the add in one subroutine and then
>>placed the actual record addition in a different subroutine
>>called from the first. That's good practice, because you may end
>>up needing to do the record addition from different contexts
>>(and, as it turns out, that's precisely the case). But the
>>problem was that the subroutine for adding the record was
>>hardwired to the fields on the dialog form. So, roughing it out,
>>you had something like this:
>>
>> Public Sub AddPersonDialog ()
>> DoCmd.OpenForm "dlgAddPerson", ,,,acDialog
>> [check if you're supposed to add]
>> Call AddPerson
>> End Sub
>>
>> Public Sub AddPerson()
>> Dim strSQL as String
>> Dim strValues as String
>>
>> strValues = VALUES (" &
>> strValues = "'" & Forms!dlgAddPer son!txtFirstNam e & "', "
>> strValues = strValues & "'" & Forms!dlgAddPer son!txtLastName
>> _
>> & "'"
>> strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
>> strSQL = strSQL & " VALUES(" & strValues & ");"
>> dbCurrent.Execu te strSQL, dbFailOnError
>> End Sub
>>
>>Now, the problem from my point of view is that the AddPerson code
>>is only valid if called from AddPersonDialog . I changed AddPerson
>>to use parameters passed to it, some of which are optional.[/color]
>
>Again, that's great, but why not wait until the first time that
>abstraction is needed, then refactor. . . .[/color]
Because at that time the code will not necessarily be fresh in my
head. Also, references to controls outside a subroutine violates
one of my basic coding rules, which I learned for good reason.
[color=blue]
> . . . If it's never needed,
>you've saved time. As you showed by your clean-up, the code was
>not hard to generalize after the fact, and by adding optional
>parameters, you did not break the code that was using the function
>previously by doing it. When I did generalize the code, I think I
>might actually make a class for this, so you can do...[/color]
Actually, I *did* break it because I did more than just add
optional arguments.
And I needed the change TODAY, less than a week after I implemented
it, and I *knew* that is was likely that I would need it.
[color=blue]
>With New clsPerson
> .FirstName = ...: .LastName = ...
> .SaveNew
> ... = .PersonID
>End With[/color]
Yes, I considered a class for this, but that was terrible overkill
for this application -- a definite case where that would be work
that was not necessary to get the thing working well.
I use classes a lot for this kind of thing, but only when the
process being encapsulated is substantially more complex than this
one, and only when it is also needed from two or more contexts. I
don't see any value in creating a Person class for this particular
application, though, if I did it once, I could use it in a lot of
apps, as I use basically the same structure for every tblPerson in
every one of my applications.
Of course, the one in question actually has a schema I didn't
design, so it doesn't exactly match my usually schema.
[color=blue][color=green]
>>I did lots of other things, such as converting both to functions
>>so I could return the PersonID of the newly inserted record so I
>>could navigate to it, but the main issue is that the structure
>>has to be appropriate and that certain principles are important
>>so that the code you write performs well in the scope for which
>>it is conceived.[/color]
>
>An what is that scope? How far ahead, and around how many
>possible turns do you look? . . .[/color]
I'm not recommending spending 8 hours thinking about all the
possibilities. I'm suggesting using your experience, as in the
Address schema example above, to make an educated guess about what
kinds of extensions are likely and then designing an architectures
for extensibility, *as long as it doesn't increase the amount of
work* to get the job at hand done.
[color=blue]
> . . . Any give feature could creep to use
>up the available time for a project, and only 10% of the projected
>needs would ever be actualized. . . .[/color]
But you can plan an architecture that is not going to get in the
way of those future needs. It's like building a house. The heating
contractor could simply run the heating ducts wherever he wanted,
and later it might get in the way of something else. So, an
architect will consider the likely future needs and design the
location of important heating ducts in order that they don't
interfere with other design components. Does it take the architect
longer to do that? Well, if the alternative is *no* design, I guess
so. But if there's a plan, it doesn't take longer to plan one way
than it takes to plan another. And will it take the heating guy
longer to put the ducts here as opposed to over there--> ? Perhaps
not, though that depends, of course.
And my point here is that you consider the costs of *how* you
implement what your implementing now. To be clear, my issue here is
not with *what* you implement, but how you do it. It's on the
question of HOW that I'm recommending more consideration of
possible future needs, and when the time is equivalent between two
alternatives (more or less) choose the more flexible alternative.
[color=blue]
> . . . I know you're aware of this, and
>not going to extremes, or you'd never finish a project, but it's
>easy to go overboard. Additionally, features sometimes get
>removed from the spec later, so then how valuable was the time
>making sure the code was general enough for possilbe future needs?[/color]
Well, I used one of the features the day I did the revision
(navigating to the PK returned by the functions) and I'm in the
middle of using the code today in a different context (to add a
different kind of person that has a different set of required
fields).
Given that navigating to the newly added record is a standard
practice of mine and given that I already knew there were at least
two different kinds of Persons needed in this application, the
architectural changes to allow for those were quite easily
foreseeable as necessary and as something that would, in fact, get
used in the product delivered to the client.
Now, there are a number of ways I could have accomplished that, the
easiest being just to write code specific to the two contexts. I'm
sure we're both allergic to that, since it means code duplication.
Been there, done that. In the present case I revised the code to
meet certain code standards that I use in all my apps for this kind
of component (I did not import from a pre-existing model because
each instance has way too many specifics that are different; a
couple of weeks ago I *did* import to a different app, and found
that it was a pain adapting the code to that context; of course, I
may have simply chosen the wrong import source, as it was from an
app that had non-standard field and table names compared to my
usual apps), because it's a task that I know something about,
having implemented it in many different apps in a particular
fashion.
In other words, this was not unknown territory for me. It's a task
that I've implemented in many different ways over the years and
I've developed some preferences about how it should be done and how
it is done most efficiently. So, I was using my experience to guide
me in the design, based on my knowledge of what's likely to be
needed later on.
[color=blue]
>...
>[color=green]
>>My point is that I believe it's important to consider the
>>architectur e on the front end, regardless of whether you ever end
>>up implementing the more complex functionality. I don't see that
>>writing the above as two subroutines is any more complicated than
>>doing it in one sub, from the standpoint of the amount of time it
>>takes to get it done. In other words, the flexibility you gain
>>from abstracting the parts of the process into independent subs
>>does not really cost you anything in terms of time on the front
>>end.[/color]
>
>If the cost truly is negligible, then go ahead. Frequently, it's
>not. In fact, playing with design improvements of small features
>can add up to a huge time eater by the end of a project since a
>project is, ultimately, a huge number of small features conencted
>together. Also, frequently, the type of abstraction that's
>required later is not the one you planned ahead for.[/color]
Separating the opening of the form from the code that adds the
record is not going to be hard, and it's also something that is
much easier on the front end than it is months later if you find
you need that abstraction. Also, making code independent of
particular controls on forms on the front end does not really take
more time than hardwiring the control names.
But you have to make those decisions *before* you write the code in
order to get the benefit of doing it right. If you don't think
through it, you're definitely going to end up wasting time *if* you
have to extend the code.
For the particular examples I've included here, I don't think that
doing it the "right" way takes longer than doing it "wrong." And my
point is that you really do have to take the time *before you write
a line of code* to decide which way to go. And I would argue that
you can design your code in a fashion that is extensible without it
taking any longer than writing the same code in a non-extensible
fashion.
[color=blue][color=green]
>>And that's where I'm concerned about your approach, that you're
>>not considering the big picture sufficiently. I have too much
>>code where I didn't consider expandability in designing the
>>architectur e and it eventually had to be significantly
>>re-architected. I think that considering that possibility on the
>>front end can lead to some important decisions on the front end
>>that are not time sinks at the time you think about them and can
>>pay off big time later on. And if you never do the expansion
>>later on, you haven't wasted any major time, either.[/color]
>
>I'm choosing to look at the big picture less up front. . . .[/color]
Yes, I know that, and I'm taking issue with your approach.
[color=blue]
> . . . What you
>may not be getting about this approach is that 80% of the time, I
>end up implementing the abstraction I would have implemented up
>front within hours or days of the initial code because it -does-
>turn out to be needed. I just think I do a better job of doing
>the abstraction when I have the real-world requirement in front of
>me at the time rather than when i'm making educated guesses about
>what it's going to be. I've also had time to meditate on how I
>would best implement the abstraction when the need does come
>along. And finally, often a different refactoring has occurred
>along a different dimesion affecting that code -before- the
>abstraction in question has become required, so this way I've got
>my horse before my cart.[/color]
Would you ever write an AddPerson routine with hardwired control
references? If not, then you're in my camp already, because you
recognize that this is a situation where it takes no longer to do
it the extensible way than it does to do it the hard-wired way.
[color=blue][color=green]
>>The issue is where to draw the line, when you actually say "well,
>>designing for that eventuality will take 45 minutes and if I
>>don't implement it later, that will be wasted" vs. "designing for
>>that will take 10 more minutes, so it doesn't matter if it's
>>never specifically used." I probably wouldn't do the 45 minutes,
>>but I'd surely do the 10 minutes. I have the feeling that you
>>wouldn't do the 10 minutes nowadays, and I think that's
>>problematic .[/color]
>
>I guess part of it is that I don't trust my 10 minutes, and lots
>of 10 minute increments over a day can add up big time, and some
>of the the extra work went into will actually turn out to be
>disposable scaffolding.
>[color=green]
>>In other words, I think it's more important to spend more time
>>THINKING and less time CODING.[/color]
>
>What about using coding as a tool for thinking. . . .[/color]
For the same reason that I think about things before I start
writing, because we have a tendency to keep anything we've put down
-- we never want to toss it once it's been committed to paper. In
learning how to write I've found that editing is the hardest part.
My dissertation is about 1/3 finished. I have about 150 pages in
finished draft. I also have files of about 75 pages more that were
ruthlessly cut from the original drafts at various times because I
determined that they weren't necessary. I'm keeping them because I
may use some of them in different parts of the dissertation. But
that was some of the hardest editing I ever did.
[color=blue]
> . . . Try it out in
>code - see it in black and white. It's easy to spend a long time
>imagining possible designs before coding when it might be more
>fruitful to implement somthing haphazardly in code, then refactor
>until it's clean. If you hit a blind alley, throw it away. That
>was part of the thinking.[/color]
I could simply not work that way. I need to have a roadmap of what
I'm doing, a plan for the flow, a plan for the components and how
they work together, before I can really code. When I don't do that,
I end up with spaghetti.
--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
nospam@nospam.n ospam (Steve Jorgensen) wrote in
<esbcmvo1edtu16 7bol6o48o0p2vl0 esdif@4ax.com>:
[color=blue]
>On Mon, 15 Sep 2003 20:33:00 GMT, dXXXfenton@bway .net (David W.
>Fenton) wrote:
>
>...[color=green]
>>
>>These are my principles, which I think are in agreement with
>>yours, but you have different emphasis:
>>
>>1. code for the task at hand.
>>
>>2. code in a fashion that will require minimal change if the code
>>needs to be enhanced.
>>
>>We agree on that, but where we disagree is on how much work goes
>>into determining #2. I think you need to think carefully about
>>structure before you implement and make sure that you do as much
>>as you can to structure your code to make it independent of
>>future changes.
>>
>>And example from last week:
>>
>>I had hired somebody to do a little work for me and when I got
>>the results, he had followed my instructions, insofar as I'd been
>>clear, but he'd done it in a fashion that was not as flexible as
>>what I wanted. It involved creating a dialog form to collect the
>>required fields for adding a new record to a person table. My
>>approach to dialogs is that the dialog knows *nothing* about the
>>environment outside itself. Secondary to that is that the dialog
>>itself should be called from one piece of code only, so that the
>>only code that knows anything about the dialog is the code that
>>opens it and closes it (though a multi-purpose dialog may have
>>more than one calling code context).[/color]
>
>Well, I would argue that it's OK to do something simple that works
>for a single case, then extend it when (and if) the second case
>arises. . . .[/color]
What if you are pretty damned sure the second case will arise?
What if it doesn't take any more work to code for the second case
than it does to code for the first?
[color=blue]
> . . . When the second case comes along, I would approach it
>with the strategy of "Rape and paste, then refactor".
>Here, you simply cut and paste the code, form, etc., change what's
>different for the second case, then gradually refactor out
>duplication between the cases starting with the lowest hanging
>fruit (biggest chunks that are easiest to grab). When you're
>done, you have basically the goal you were describing above.[/color]
I think it's easier to choose an architecture that has no
unnecessary dependencies on the specifics of its initial
implementation.
In schema design, say you had an application where in the original
design, everyone was absolutely certain that there'd never be a
need for more than one address per person. So, you put the address
in the Person table, and then they decide they need a second
address, so then you move to a 1:N address table and restructure
the existing data accordingly.
If you'd put the address in a 1:1 table, though, you would have had
very little work to change the relationship to 1:N. You might think
that implementing the 1:1 address would require a more complex UI,
but it actually doesn't at all -- you just join the address table
in the recordsource of your person form and plop the fields on your
form. When you convert to 1:N, then you have to change the
recordsource to take out the join to the address table and create a
subform for the addresses and remove the existing address fields
from your Person form.
Do you do all the work preparing for the change on the front end?
ABSOLUTELY NOT.
But you choose a STRUCTURE that gives you maximum flexibility along
lines that are foreseeable at design time.
In terms of implementation, the 1:1 address table takes no more
time than putting the fields in the Person table. In terms of UI,
it is indistinguishab le to the users. But in terms of flexibility,
you save all that time restructuring existing data. Also, if you
got any lookup routines that use addresses, you don't have to
revise those in any significant way when you change to 1:N for the
addresses.
To me, it's a no-brainer -- you do the 1:1 table on the front just
in case you need 1:N later, and the *cost* of doing so is basically
nothing.
That's the kind of situation I'm talking about, where you have a
choice between two methods that take the same amount of time to
implement (more or less), but one of which allows more future
flexibility, *even if you end up never needing it*.
[color=blue]
>While refactoring, look for any functionality similar to something
>that exists elsewhere in the code, and use it if it's pluggable.
>If it's not pluggable, add a comment there, finish the current
>refactoring cycle, then go back to the comment and refactor again
>to remove duplication with the other code. Repeat until beauty
>arises.[/color]
If the basic structure is there already, you don't have to do
nearly as much reworking, as in the schema example above.
[color=blue][color=green]
>>Now, the problem with the code I got from this programmer was
>>that he had rightly separated out the opening of the form to
>>collect the information for the add in one subroutine and then
>>placed the actual record addition in a different subroutine
>>called from the first. That's good practice, because you may end
>>up needing to do the record addition from different contexts
>>(and, as it turns out, that's precisely the case). But the
>>problem was that the subroutine for adding the record was
>>hardwired to the fields on the dialog form. So, roughing it out,
>>you had something like this:
>>
>> Public Sub AddPersonDialog ()
>> DoCmd.OpenForm "dlgAddPerson", ,,,acDialog
>> [check if you're supposed to add]
>> Call AddPerson
>> End Sub
>>
>> Public Sub AddPerson()
>> Dim strSQL as String
>> Dim strValues as String
>>
>> strValues = VALUES (" &
>> strValues = "'" & Forms!dlgAddPer son!txtFirstNam e & "', "
>> strValues = strValues & "'" & Forms!dlgAddPer son!txtLastName
>> _
>> & "'"
>> strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
>> strSQL = strSQL & " VALUES(" & strValues & ");"
>> dbCurrent.Execu te strSQL, dbFailOnError
>> End Sub
>>
>>Now, the problem from my point of view is that the AddPerson code
>>is only valid if called from AddPersonDialog . I changed AddPerson
>>to use parameters passed to it, some of which are optional.[/color]
>
>Again, that's great, but why not wait until the first time that
>abstraction is needed, then refactor. . . .[/color]
Because at that time the code will not necessarily be fresh in my
head. Also, references to controls outside a subroutine violates
one of my basic coding rules, which I learned for good reason.
[color=blue]
> . . . If it's never needed,
>you've saved time. As you showed by your clean-up, the code was
>not hard to generalize after the fact, and by adding optional
>parameters, you did not break the code that was using the function
>previously by doing it. When I did generalize the code, I think I
>might actually make a class for this, so you can do...[/color]
Actually, I *did* break it because I did more than just add
optional arguments.
And I needed the change TODAY, less than a week after I implemented
it, and I *knew* that is was likely that I would need it.
[color=blue]
>With New clsPerson
> .FirstName = ...: .LastName = ...
> .SaveNew
> ... = .PersonID
>End With[/color]
Yes, I considered a class for this, but that was terrible overkill
for this application -- a definite case where that would be work
that was not necessary to get the thing working well.
I use classes a lot for this kind of thing, but only when the
process being encapsulated is substantially more complex than this
one, and only when it is also needed from two or more contexts. I
don't see any value in creating a Person class for this particular
application, though, if I did it once, I could use it in a lot of
apps, as I use basically the same structure for every tblPerson in
every one of my applications.
Of course, the one in question actually has a schema I didn't
design, so it doesn't exactly match my usually schema.
[color=blue][color=green]
>>I did lots of other things, such as converting both to functions
>>so I could return the PersonID of the newly inserted record so I
>>could navigate to it, but the main issue is that the structure
>>has to be appropriate and that certain principles are important
>>so that the code you write performs well in the scope for which
>>it is conceived.[/color]
>
>An what is that scope? How far ahead, and around how many
>possible turns do you look? . . .[/color]
I'm not recommending spending 8 hours thinking about all the
possibilities. I'm suggesting using your experience, as in the
Address schema example above, to make an educated guess about what
kinds of extensions are likely and then designing an architectures
for extensibility, *as long as it doesn't increase the amount of
work* to get the job at hand done.
[color=blue]
> . . . Any give feature could creep to use
>up the available time for a project, and only 10% of the projected
>needs would ever be actualized. . . .[/color]
But you can plan an architecture that is not going to get in the
way of those future needs. It's like building a house. The heating
contractor could simply run the heating ducts wherever he wanted,
and later it might get in the way of something else. So, an
architect will consider the likely future needs and design the
location of important heating ducts in order that they don't
interfere with other design components. Does it take the architect
longer to do that? Well, if the alternative is *no* design, I guess
so. But if there's a plan, it doesn't take longer to plan one way
than it takes to plan another. And will it take the heating guy
longer to put the ducts here as opposed to over there--> ? Perhaps
not, though that depends, of course.
And my point here is that you consider the costs of *how* you
implement what your implementing now. To be clear, my issue here is
not with *what* you implement, but how you do it. It's on the
question of HOW that I'm recommending more consideration of
possible future needs, and when the time is equivalent between two
alternatives (more or less) choose the more flexible alternative.
[color=blue]
> . . . I know you're aware of this, and
>not going to extremes, or you'd never finish a project, but it's
>easy to go overboard. Additionally, features sometimes get
>removed from the spec later, so then how valuable was the time
>making sure the code was general enough for possilbe future needs?[/color]
Well, I used one of the features the day I did the revision
(navigating to the PK returned by the functions) and I'm in the
middle of using the code today in a different context (to add a
different kind of person that has a different set of required
fields).
Given that navigating to the newly added record is a standard
practice of mine and given that I already knew there were at least
two different kinds of Persons needed in this application, the
architectural changes to allow for those were quite easily
foreseeable as necessary and as something that would, in fact, get
used in the product delivered to the client.
Now, there are a number of ways I could have accomplished that, the
easiest being just to write code specific to the two contexts. I'm
sure we're both allergic to that, since it means code duplication.
Been there, done that. In the present case I revised the code to
meet certain code standards that I use in all my apps for this kind
of component (I did not import from a pre-existing model because
each instance has way too many specifics that are different; a
couple of weeks ago I *did* import to a different app, and found
that it was a pain adapting the code to that context; of course, I
may have simply chosen the wrong import source, as it was from an
app that had non-standard field and table names compared to my
usual apps), because it's a task that I know something about,
having implemented it in many different apps in a particular
fashion.
In other words, this was not unknown territory for me. It's a task
that I've implemented in many different ways over the years and
I've developed some preferences about how it should be done and how
it is done most efficiently. So, I was using my experience to guide
me in the design, based on my knowledge of what's likely to be
needed later on.
[color=blue]
>...
>[color=green]
>>My point is that I believe it's important to consider the
>>architectur e on the front end, regardless of whether you ever end
>>up implementing the more complex functionality. I don't see that
>>writing the above as two subroutines is any more complicated than
>>doing it in one sub, from the standpoint of the amount of time it
>>takes to get it done. In other words, the flexibility you gain
>>from abstracting the parts of the process into independent subs
>>does not really cost you anything in terms of time on the front
>>end.[/color]
>
>If the cost truly is negligible, then go ahead. Frequently, it's
>not. In fact, playing with design improvements of small features
>can add up to a huge time eater by the end of a project since a
>project is, ultimately, a huge number of small features conencted
>together. Also, frequently, the type of abstraction that's
>required later is not the one you planned ahead for.[/color]
Separating the opening of the form from the code that adds the
record is not going to be hard, and it's also something that is
much easier on the front end than it is months later if you find
you need that abstraction. Also, making code independent of
particular controls on forms on the front end does not really take
more time than hardwiring the control names.
But you have to make those decisions *before* you write the code in
order to get the benefit of doing it right. If you don't think
through it, you're definitely going to end up wasting time *if* you
have to extend the code.
For the particular examples I've included here, I don't think that
doing it the "right" way takes longer than doing it "wrong." And my
point is that you really do have to take the time *before you write
a line of code* to decide which way to go. And I would argue that
you can design your code in a fashion that is extensible without it
taking any longer than writing the same code in a non-extensible
fashion.
[color=blue][color=green]
>>And that's where I'm concerned about your approach, that you're
>>not considering the big picture sufficiently. I have too much
>>code where I didn't consider expandability in designing the
>>architectur e and it eventually had to be significantly
>>re-architected. I think that considering that possibility on the
>>front end can lead to some important decisions on the front end
>>that are not time sinks at the time you think about them and can
>>pay off big time later on. And if you never do the expansion
>>later on, you haven't wasted any major time, either.[/color]
>
>I'm choosing to look at the big picture less up front. . . .[/color]
Yes, I know that, and I'm taking issue with your approach.
[color=blue]
> . . . What you
>may not be getting about this approach is that 80% of the time, I
>end up implementing the abstraction I would have implemented up
>front within hours or days of the initial code because it -does-
>turn out to be needed. I just think I do a better job of doing
>the abstraction when I have the real-world requirement in front of
>me at the time rather than when i'm making educated guesses about
>what it's going to be. I've also had time to meditate on how I
>would best implement the abstraction when the need does come
>along. And finally, often a different refactoring has occurred
>along a different dimesion affecting that code -before- the
>abstraction in question has become required, so this way I've got
>my horse before my cart.[/color]
Would you ever write an AddPerson routine with hardwired control
references? If not, then you're in my camp already, because you
recognize that this is a situation where it takes no longer to do
it the extensible way than it does to do it the hard-wired way.
[color=blue][color=green]
>>The issue is where to draw the line, when you actually say "well,
>>designing for that eventuality will take 45 minutes and if I
>>don't implement it later, that will be wasted" vs. "designing for
>>that will take 10 more minutes, so it doesn't matter if it's
>>never specifically used." I probably wouldn't do the 45 minutes,
>>but I'd surely do the 10 minutes. I have the feeling that you
>>wouldn't do the 10 minutes nowadays, and I think that's
>>problematic .[/color]
>
>I guess part of it is that I don't trust my 10 minutes, and lots
>of 10 minute increments over a day can add up big time, and some
>of the the extra work went into will actually turn out to be
>disposable scaffolding.
>[color=green]
>>In other words, I think it's more important to spend more time
>>THINKING and less time CODING.[/color]
>
>What about using coding as a tool for thinking. . . .[/color]
For the same reason that I think about things before I start
writing, because we have a tendency to keep anything we've put down
-- we never want to toss it once it's been committed to paper. In
learning how to write I've found that editing is the hardest part.
My dissertation is about 1/3 finished. I have about 150 pages in
finished draft. I also have files of about 75 pages more that were
ruthlessly cut from the original drafts at various times because I
determined that they weren't necessary. I'm keeping them because I
may use some of them in different parts of the dissertation. But
that was some of the hardest editing I ever did.
[color=blue]
> . . . Try it out in
>code - see it in black and white. It's easy to spend a long time
>imagining possible designs before coding when it might be more
>fruitful to implement somthing haphazardly in code, then refactor
>until it's clean. If you hit a blind alley, throw it away. That
>was part of the thinking.[/color]
I could simply not work that way. I need to have a roadmap of what
I'm doing, a plan for the flow, a plan for the components and how
they work together, before I can really code. When I don't do that,
I end up with spaghetti.
--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Comment