By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,446 Members | 3,090 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,446 IT Pros & Developers. It's quick & easy.

Open question - leverage all features liberally, or be selective?

P: n/a
In a recent thread, RKC (correctly, I believe), took issue with my use of
multiple parameters in a Property Let procedure to pass dimensional
arguments on the basis that, although it works, it's not obvious how the
code works if you don't know the intricacies of the Property Let/Get
syntax. Likewise, I dislike (and code to minimize the use of) the VB/VBA
syntax of returning a value by referring to the function name as if it were
a variable because this is too similar to the syntax for a recusrive
function call. I had to do some experiments to find out for sure what
happens in all cases with or without the parentheses after the function
name (David Fenton points out that there is no technical ambiguity here,
but I think this is another case of needing arcane knowledge to read some
code, and it interferes with my refactoring practices).

So, although all the features of a system (Access/VBA in this case) were
put there to add some value, perhaps it is best to come up with development
strategies and idioms that make use of only certain subsets of features in
certain clear ways to end up with code that's simpler and easier to
maintain.

OK, Me Aculpa - that's not a question, that's a soap box. Still, opinions?

I guess the opposing argumnent would be that, when a feature of the system
or language provides something you need, why not leverage that right now
rather than take time thinking of a code-around or adding extra lines of
code to a procedure (such as dimentioning a return variable which actually
adds duplication of the return type spec) or skipping a dimensional
property Let at the expense of using a function syntax rather than the more
obvious array syntax to set a value in an indexed list property.

I guess the opposing argument sounds pretty good, too - hmm?

- Steve Jorgensen
Nov 12 '05 #1
Share this Question
Share on Google+
55 Replies


P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<td********************************@4ax.com>:
(David Fenton points out that there is no technical ambiguity
here, but I think this is another case of needing arcane knowledge
to read some code, and it interferes with my refactoring
practices).


That other thread has expired from my news server, so, having read
your answer on Google, I'll respond to this point here:

I don't see a damned thing about this that is "arcane." It's the
way functions work, whether user-defined or built-in. If you don't
know how that works, then you really aren't skilled in VBA, and you
probably have far worse problems with your coding than anything
your suggestions would address.

Knowledge of how a particular language works is not something that
I consider "arcane" knowledge -- it's just the basics of being
fluent in the programming language. You're point of view might very
well make sense for beginning programmers, at a certain level, but
I'm not sure that it would do anything to help them understand how
VBA actually works. Because of that, I don't see the value.

But, we all have our own coding styles.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #2

P: n/a
On Sun, 14 Sep 2003 21:29:30 GMT, dX********@bway.net (David W. Fenton)
wrote:
no****@nospam.nospam (Steve Jorgensen) wrote in
<td********************************@4ax.com>:
(David Fenton points out that there is no technical ambiguity
here, but I think this is another case of needing arcane knowledge
to read some code, and it interferes with my refactoring
practices).
That other thread has expired from my news server, so, having read
your answer on Google, I'll respond to this point here:

I don't see a damned thing about this that is "arcane." It's the
way functions work, whether user-defined or built-in. If you don't
know how that works, then you really aren't skilled in VBA, and you
probably have far worse problems with your coding than anything
your suggestions would address.


Well, I consider myself very good at VB/VBA in spite of some long standing
gaps in my knowledge that have recently been exposed (Choose is a VBA,
function - doh!). Still, I did not know how different references to the
function name from within the function would behave. This is because I
chose early on not to code in a style that would use that feature much
because I thought it was ugly.

What I'm aimimg for, these days, is code that speaks clearly, not just that
speaks clearly if you're savvy with the language I wrote it in. I can read
books on Java, for instance, and see some code examples that look like they
were written by Java experts, but they're inscrutable, and other examples
doing equally challenging things that can be read by pretty much anyone
with no Java knowledge at all. I would argue that the one that's easier to
read with no special knowledge is easier to maintain even by someone well
versed in the language. Very clear code is also kind of like a clean
office - it's just more pleasant to work in and easier to be productive
with.
Knowledge of how a particular language works is not something that
I consider "arcane" knowledge -- it's just the basics of being
Arcane may be overstating the point, but I still think code that is obvious
may be preferable to code that is not for that reason alone.
fluent in the programming language. You're point of view might very
well make sense for beginning programmers, at a certain level, but
I'm not sure that it would do anything to help them understand how
VBA actually works. Because of that, I don't see the value.

But, we all have our own coding styles.


Well, this could all just be my backlash to the truly arcane code I used to
be in the habit of writing. I would optimize as I went, try to leave hooks
for everything that might need to happen, etc. I'm swinging the pendulum
back the other way, and prioritizing clarity and simplicity, optimizing
only when there is a performance issue, and optimizing just what's slow,
adding functionality when I find that it's needed, and refactoring as
necessary at the time, using long names, using discriptive temporary
variables for parts of calculations, etc.

So Perhaps, I am going overboard on aiming for clarity and simplicity now
when I speak of simply avoiding the use of functionality that is not
completely obvious, but I'm not yet convinced.
Nov 12 '05 #3

P: n/a

[Editor's Note: "Steve Jorgensen" is a charter member of Access Morons.
This is Number 233 in his long-running moronic series.]
"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:td********************************@4ax.com...
In a recent thread, RKC (correctly, I believe), took issue with my use of
multiple parameters in a Property Let procedure to pass dimensional
arguments on the basis that, although it works, it's not obvious how the
code works if you don't know the intricacies of the Property Let/Get
syntax. Likewise, I dislike (and code to minimize the use of) the VB/VBA
syntax of returning a value by referring to the function name as if it were a variable because this is too similar to the syntax for a recusrive
function call. I had to do some experiments to find out for sure what
happens in all cases with or without the parentheses after the function
name (David Fenton points out that there is no technical ambiguity here,
but I think this is another case of needing arcane knowledge to read some
code, and it interferes with my refactoring practices).

So, although all the features of a system (Access/VBA in this case) were
put there to add some value, perhaps it is best to come up with development strategies and idioms that make use of only certain subsets of features in
certain clear ways to end up with code that's simpler and easier to
maintain.

OK, Me Aculpa - that's not a question, that's a soap box. Still, opinions?
I guess the opposing argumnent would be that, when a feature of the system
or language provides something you need, why not leverage that right now
rather than take time thinking of a code-around or adding extra lines of
code to a procedure (such as dimentioning a return variable which actually
adds duplication of the return type spec) or skipping a dimensional
property Let at the expense of using a function syntax rather than the more obvious array syntax to set a value in an indexed list property.

I guess the opposing argument sounds pretty good, too - hmm?

- Steve Jorgensen

Nov 12 '05 #4

P: n/a
On Mon, 15 Sep 2003 00:50:49 GMT, "XMVP" <ac***********@hotmail.com> wrote:

[Editor's Note: "Steve Jorgensen" is a charter member of Access Morons.
This is Number 233 in his long-running moronic series.]


People who live in glass houses should stay off of Usenet.
Nov 12 '05 #5

P: n/a
Steve Jorgensen <no****@nospam.nospam> wrote in message news:<td********************************@4ax.com>. ..
<snipperels>
Likewise, I dislike (and code to minimize the use of) the VB/VBA
syntax of returning a value by referring to the function name as if it were
a variable because this is too similar to the syntax for a recusrive
function call.


Huh? Is this what you mean?
Private Function cbfFoo As Boolean

cbfBoo = False

End Function

=====================

Private Sub cbfMySub()

If (cbfBoo) Then

:::

End Sub

=======================

If not, what? If so, what the blue blazes could you possible find
"arcane" or "recursive" about it?

O, and by the way it's "mea culpa", not "me aculpa" just in case it
wasn't a typo.

Edward
Nov 12 '05 #6

P: n/a
rkc

"Edward" <te********@hotmail.com> wrote in message
news:25**************************@posting.google.c om...
Huh? Is this what you mean?
Private Function cbfFoo As Boolean

cbfBoo = False

End Function

More like

Private Function cbfFoo As Boolean

If BibiddyBobiddyBoo then
cbfBoo = True
Else if WhopBobaLoo then
cbfBoo = True
Else if WhopBangBoom And YabbaDabbaDooThen
cbfBoo = True
End if

End Function

If not, what? If so, what the blue blazes could you possible find
"arcane" or "recursive" about it?


Nothing if you understand the difference between assigning a return
value to a function and calling a function.

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant unless
it was already set to true.

Nov 12 '05 #7

P: n/a
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

....

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant unless
it was already set to true.


I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the return value
to False for a particular case, is that because you knew the default would
be False, and that's what you wanted to return, or is it because you forgot
to set the return value? Explicitly returning False makes it clear when
re-reading the code that you made a conscious decision to return False.

I'm not saying never to skip blocks to handle default cases (in fact,
that's a good thing), but if I do that, I like to put a line at the top
that explicitly assigns the default value rather than leaving it implicit.
Nov 12 '05 #8

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<lk********************************@4ax.com>:
Well, this could all just be my backlash to the truly arcane code
I used to be in the habit of writing. I would optimize as I went,
try to leave hooks for everything that might need to happen, etc.
I'm swinging the pendulum back the other way, and prioritizing
clarity and simplicity, optimizing only when there is a
performance issue, and optimizing just what's slow, adding
functionality when I find that it's needed, and refactoring as
necessary at the time, using long names, using discriptive
temporary variables for parts of calculations, etc.

So Perhaps, I am going overboard on aiming for clarity and
simplicity now when I speak of simply avoiding the use of
functionality that is not completely obvious, but I'm not yet
convinced.


I think that the discussion about returning ordinal numbers is
illuminating. You recommended CHOOSE() which I think is bad. Why do
I think it's bad? Because it works only for the simplest case. I
just spent an hour or so engineering the structure to handle
returning a string value for any number and returning an ordinal
string for any number. I learned a lot by doing it, and if I ever
need it, I can go back and finish it up (I discovered and noted in
the code a few architectural problems but didn't bother to actual
fix them now).

My point of view is this:

1. when you're coding for a project and need to get it done, do the
simplest possible method.

2. when you're coding for your own library, code the most robust
and most flexible version you can.

3. when you're doing both, figure out what you can do on the
client's dime and get it done, but then re-engineer for
re-usability.

To me, the CHOOSE() solution doesn't get you very far -- it can
solve a single problem, but the next time you need ordinals for a
wider range, then you'll have to go back to the drawing board.

I'm almost certain that this has already been solved and that I
could go to the Access Web and pick up code that already does this
(yes, http://www.mvps.org/access/modules/mdl0047.htm, does most of
it already, though I haven't downloaded it and looked at it given
that it claims to be polyglot, it would need different logic for
different languages), but I wanted to look at the problem as a fun
thing to have a go at, in order to figure some things out for
myself about coding.

The method you choose to accomplish a particular task will be
determined by how you define the task. In this case, I criticized
the method because I feel the scope is too narrowly defined to be
terribly useful.

And that's one of the things I fear about your posts, Steve -- you
seem to be swinging to the other extreme, always coding for the
moment and not doing enough consideration of larger issues.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #9

P: n/a
On Mon, 15 Sep 2003 17:31:19 GMT in comp.databases.ms-access, Steve
Jorgensen <no****@nospam.nospam> wrote:
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant unless
it was already set to true.


I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the return value
to False for a particular case, is that because you knew the default would
be False, and that's what you wanted to return, or is it because you forgot
to set the return value? Explicitly returning False makes it clear when
re-reading the code that you made a conscious decision to return False.

I'm not saying never to skip blocks to handle default cases (in fact,
that's a good thing), but if I do that, I like to put a line at the top
that explicitly assigns the default value rather than leaving it implicit.


For me it would depend on the complexity of the function, e.g.

This is so simple it's clear
Function IsNothing(pobj As Object) As Boolean
If pobj Is Nothing Then
IsNothing=True
End If
End Function

But can be further shortened to
Function IsNothing(pobj As Object) As Boolean
IsNothing = pobj Is Nothing
End Function

In some circumstances I might use an explicit setting of my boolean
variable to False for clarity's sake, other times I might skip, e.g.

Function ArrayContains(pArray(), pstring) As Boolean
Dim i as long
Dim bReturn as boolean
(optionally bReturn=False here)
for i=lbound(pArray) to ubound(pArray)
if pArray(i) like "*" & pstring & "*" Then
bReturn =True
exit for
End if
Next i
ArrayContains = bReturn
End Function

The above has no actual case where to set bReturn=False except before
where it starts processing.

--
A)bort, R)etry, I)nfluence with large hammer.

(replace sithlord with trevor for email)
Nov 12 '05 #10

P: n/a
On Mon, 15 Sep 2003 17:52:51 GMT, dX********@bway.net (David W. Fenton)
wrote:
no****@nospam.nospam (Steve Jorgensen) wrote in
<lk********************************@4ax.com>:
Well, this could all just be my backlash to the truly arcane code
I used to be in the habit of writing. I would optimize as I went,
try to leave hooks for everything that might need to happen, etc.
I'm swinging the pendulum back the other way, and prioritizing
clarity and simplicity, optimizing only when there is a
performance issue, and optimizing just what's slow, adding
functionality when I find that it's needed, and refactoring as
necessary at the time, using long names, using discriptive
temporary variables for parts of calculations, etc.

So Perhaps, I am going overboard on aiming for clarity and
simplicity now when I speak of simply avoiding the use of
functionality that is not completely obvious, but I'm not yet
convinced.
I think that the discussion about returning ordinal numbers is
illuminating. You recommended CHOOSE() which I think is bad. Why do
I think it's bad? Because it works only for the simplest case. I
just spent an hour or so engineering the structure to handle
returning a string value for any number and returning an ordinal
string for any number. I learned a lot by doing it, and if I ever
need it, I can go back and finish it up (I discovered and noted in
the code a few architectural problems but didn't bother to actual
fix them now).


But, is the best time to do that when you only need First through Fourth,
or when you are asked for a set that goes to Twenty First? If you code for
the general case up front, do you bill the time to the client?
My point of view is this:

1. when you're coding for a project and need to get it done, do the
simplest possible method.
Ah - that answers my previous question. We are in agreement on this, then.
2. when you're coding for your own library, code the most robust
and most flexible version you can.
That's what I used to do. Now, instead, each time I need a more general
case of something in my library than what I've written before, I make the
improvement right in the project I'm working on, then import the change
into my main library. I keep the latest copy of my library with me at all
times, so I can import the newest version each time I revisit a project.
3. when you're doing both, figure out what you can do on the
client's dime and get it done, but then re-engineer for
re-usability.
This is exactly the philosophy I worked with until about a month ago, but
I'm trying on a different approach...
Reingineer for clarity and simplicitly immediately, and put it directly on
the client's dime because it will impact that project directly (possibly
within mere hours or minutes), but re-engineer to handle more general cases
later when they come up in a project. Why? Because you don't know what
the next important case to handle will be, and it could mean refactoring
lots of existing pieces, etc. This is easier to do, the simpler the
initial code is.
If the initial code already has been made more complex to handle cases that
have not yet arisen, they're harder to refactor. So, when the
functionality you would have put in up front actually does become needed,
you implement it from the state of the code at that time. As a metaphor,
when rearranging a living room, why place the sofa in the middle of the
room without knowing where it's going to be placed, then have to move other
pieces around it? Instead, why not bring in the sofa later when you know
where to place it.
To me, the CHOOSE() solution doesn't get you very far -- it can
solve a single problem, but the next time you need ordinals for a
wider range, then you'll have to go back to the drawing board.
It gets you as far as having a defined central location and syntax for the
function that does the job in the application, and an implementation that
works for the currently needed cases. If the body will have to be rebuilt
later, no big deal. There wasn't that much work up front to feel bad about
losing.
I'm almost certain that this has already been solved and that I
could go to the Access Web and pick up code that already does this
(yes, http://www.mvps.org/access/modules/mdl0047.htm, does most of
it already, though I haven't downloaded it and looked at it given
that it claims to be polyglot, it would need different logic for
different languages), but I wanted to look at the problem as a fun
thing to have a go at, in order to figure some things out for
myself about coding.
I certainly understand that one. I would still, then choose to leave the
fuller implentation outside of my core library until I needed it. Upon
applying it for the fisrt time, I might see a simpler implementation, or I
might have developed other functions in the mean time that can assist with
parts of the problem.
The method you choose to accomplish a particular task will be
determined by how you define the task. In this case, I criticized
the method because I feel the scope is too narrowly defined to be
terribly useful.

And that's one of the things I fear about your posts, Steve -- you
seem to be swinging to the other extreme, always coding for the
moment and not doing enough consideration of larger issues.


Yes, that's what I'm doing, but I'm not sure the characterization fits.
The reason I (and possilby you as well) developed the habit of trying to
account for everything that might happen later up front was because I did
not develop techniqes making big changes to code later without fear of
breakage.
Now, learning new tricks for removing duplication and learning to isolate
the task of refactoring from the task of adding functionality (rather than
do them at the same time), I find it's much easier than it used to be to
make big changes to the code later, and it's easier still, the simpler the
initial code is. Having more functionality than what's required can
actually make it harder to add functinoality later. Also, the more I am
coding by cycles of enhancing, refactoring..., the more I find the code
tends to evolve into forms that are easier to change. The code was not as
"designed" as it used to be, but it can end up looking like it was designed
by someone smarter than I.
Nov 12 '05 #11

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<5f********************************@4ax.com>:
On Mon, 15 Sep 2003 17:52:51 GMT, dX********@bway.net (David W.
Fenton) wrote:
And that's one of the things I fear about your posts, Steve --
you seem to be swinging to the other extreme, always coding for
the moment and not doing enough consideration of larger issues.


Yes, that's what I'm doing, but I'm not sure the characterization
fits. The reason I (and possilby you as well) developed the habit
of trying to account for everything that might happen later up
front was because I did not develop techniqes making big changes
to code later without fear of breakage.
Now, learning new tricks for removing duplication and learning to
isolate the task of refactoring from the task of adding
functionality (rather than do them at the same time), I find it's
much easier than it used to be to make big changes to the code
later, and it's easier still, the simpler the initial code is.
Having more functionality than what's required can actually make
it harder to add functinoality later. Also, the more I am coding
by cycles of enhancing, refactoring..., the more I find the code
tends to evolve into forms that are easier to change. The code
was not as "designed" as it used to be, but it can end up looking
like it was designed by someone smarter than I.


Well, I think it's all about design.

Your point about wrapping Choose() in a function and then using
that function is a good one -- you have a single function and when
functionality needs to be extended it can be done without needing
to recode the parts of the application that used the original
function.

But that's the issue here, to me. You said something about a SELECT
CASE being too unwieldy for this task. I said that a SELECT CASE is
the right thing if the scope justifies it. Indeed, if you're going
to create something that is versatile, SELECT CASE is the only
efficient way to do it.

I was objecting to your rejection of an implementation possibility
because, I guess, I was reading it more broadly than you intended.

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).

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!dlgAddPerson!txtFirstName & "', "
strValues = strValues & "'" & Forms!dlgAddPerson!txtLastName _
& "'"
strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
strSQL = strSQL & " VALUES(" & strValues & ");"
dbCurrent.Execute 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.

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.

It's quite possible to collapse both of these into a single
subroutine, but I would say it's a bad idea to do that because it
then requires a re-arranging of the architecture.

The two subroutine architecture with no dependencies on context
will work no matter what you do to change the whole procedure. The
method of adding the record can be changed to a recordset without
requiring any change to the calling code.

Now, returning the added PK and navigating to it is very different,
as it requires changing everything, including the call to the
AddPersonDialog subroutine in the original context.

My point is that I believe it's important to consider the
architecture 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.

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 architecture
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.

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.

In other words, I think it's more important to spend more time
THINKING and less time CODING.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #12

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<cj********************************@4ax.com>:
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant
unless it was already set to true.


I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the
return value to False for a particular case, is that because you
knew the default would be False, and that's what you wanted to
return, or is it because you forgot to set the return value?
Explicitly returning False makes it clear when re-reading the code
that you made a conscious decision to return False.

I'm not saying never to skip blocks to handle default cases (in
fact, that's a good thing), but if I do that, I like to put a line
at the top that explicitly assigns the default value rather than
leaving it implicit.


Here, again, I disagree. A Boolean function will return false
unless you set it to something else. That's bloody obvious. An
integer or long will return 0. It shouldn't need to be made clear
to the person reading the code -- it should be clear from the fact
that it's a function of a particular type.

If you want to make it clear, then include a comment.

But include a specific setting to a value that does not need to be
set is bad practice, in my opinion, because it's a line of code
that is 100% unnecessary. If you're calling the thing in a query
100K times, this might very well make a difference.

Comments are for clarifying.

Redundant lines of code can just as easily confuse the person
reading the code as clarify, as the person reading the function
might say "Wha? I must have misread this code, since I would have
thought the value would be FALSE already?" And then you waste time
walking back through the code trying to figure out why it needed to
be set to False.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #13

P: n/a
On Mon, 15 Sep 2003 20:40:57 GMT, dX********@bway.net (David W. Fenton)
wrote:
no****@nospam.nospam (Steve Jorgensen) wrote in
<cj********************************@4ax.com>:
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant
unless it was already set to true.
I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the
return value to False for a particular case, is that because you
knew the default would be False, and that's what you wanted to
return, or is it because you forgot to set the return value?
Explicitly returning False makes it clear when re-reading the code
that you made a conscious decision to return False.

I'm not saying never to skip blocks to handle default cases (in
fact, that's a good thing), but if I do that, I like to put a line
at the top that explicitly assigns the default value rather than
leaving it implicit.


Here, again, I disagree. A Boolean function will return false
unless you set it to something else. That's bloody obvious. An
integer or long will return 0. It shouldn't need to be made clear
to the person reading the code -- it should be clear from the fact
that it's a function of a particular type.

If you want to make it clear, then include a comment.


A comment would be fine, but include something. Don't just leave it
implicit, or it's not clear if you programmed by intention or by chance.
But include a specific setting to a value that does not need to be
set is bad practice, in my opinion, because it's a line of code
that is 100% unnecessary. If you're calling the thing in a query
100K times, this might very well make a difference.
If it's too slow, then optimize it, but that will probably never happen in
any given case. The optimizer may even be smart enough to NOP the line.
If you prefer to handle it with a comment, that's fine too. I can go with
that. I just don't think it's OK to do nothing to document the intention.
Comments are for clarifying.

Redundant lines of code can just as easily confuse the person
reading the code as clarify, as the person reading the function
might say "Wha? I must have misread this code, since I would have
thought the value would be FALSE already?" And then you waste time
walking back through the code trying to figure out why it needed to
be set to False.


I can see that point of view. There are, on the other hand, many coding
style documents that say never to use default initialization, and always do
it explicitly because failure to initialize is a common cause of bugs. I'd
say either doing it explicitly or adding a comment is fine, but do one or
the other religeously.
Nov 12 '05 #14

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:cj********************************@4ax.com...
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...

BTW, in case cbfBoo = False was a typo, the default value of a
boolean variable is false so setting it to false is redundant unless
it was already set to true.
I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the return value
to False for a particular case, is that because you knew the default would
be False, and that's what you wanted to return, or is it because you

forgot to set the return value? Explicitly returning False makes it clear when
re-reading the code that you made a conscious decision to return False.


I my little world it would depend on what I was checking for in the
function.
If the function was most likely to return True and only a few criteria would
make it return False then I would set the return value to True at the top
and
set it to false if one of the criteria where met. The only reason I would
do
that is to eliminate using Not.

If YabaDabbaDoo then theFunction = False instead of
If Not YabbaDabbaDoo theFunction = True.

Nov 12 '05 #15

P: n/a
On Mon, 15 Sep 2003 20:40:57 GMT in comp.databases.ms-access,
dX********@bway.net (David W. Fenton) wrote:
Here, again, I disagree.
You would! :-)
A Boolean function will return false
unless you set it to something else. That's bloody obvious. An
integer or long will return 0. It shouldn't need to be made clear
to the person reading the code -- it should be clear from the fact
that it's a function of a particular type.

If you want to make it clear, then include a comment.

But include a specific setting to a value that does not need to be
set is bad practice, in my opinion, because it's a line of code
that is 100% unnecessary. If you're calling the thing in a query
100K times, this might very well make a difference.

Comments are for clarifying.

Redundant lines of code can just as easily confuse the person
reading the code as clarify, as the person reading the function
might say "Wha? I must have misread this code, since I would have
thought the value would be FALSE already?" And then you waste time
walking back through the code trying to figure out why it needed to
be set to False.


But there's another argument, code portability. If you were to port
your function to an asp page for example, you would need that
bool=false line as there's no explicit datatypes in asp, without it
the function would return empty/nothing/whatever but not false.

But yes, in VBA or VB if called 10000 times I would skip that line.

--
A)bort, R)etry, I)nfluence with large hammer.

(replace sithlord with trevor for email)
Nov 12 '05 #16

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:d5********************************@4ax.com...
On Mon, 15 Sep 2003 21:30:06 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

I my little world it would depend on what I was checking for in the
function.
If the function was most likely to return True and only a few criteria wouldmake it return False then I would set the return value to True at the top
and
set it to false if one of the criteria where met. The only reason I woulddo
that is to eliminate using Not.

If YabaDabbaDoo then theFunction = False instead of
If Not YabbaDabbaDoo theFunction = True.


My point was that somewhere, you should make your intention clear that the
return value should be False if it was not set to True. You could do that
either with an explicit assignment before the remaining code, or as David
suggest, by including a comment expressing the intention.


I understood your point. My response included an implicit rejection of
your point. :) I think it should be clear enough that in VBA a boolean
variable is False unless it has been set to True. I'm certainly not against
documenting what the purpose of a function is, but including a comment
that says 'the return value of this function is False unless it is set to
True'
is a bit goofy.

Nov 12 '05 #17

P: n/a
On Mon, 15 Sep 2003 23:36:10 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

....
My point was that somewhere, you should make your intention clear that the
return value should be False if it was not set to True. You could do that
either with an explicit assignment before the remaining code, or as David
suggest, by including a comment expressing the intention.
I understood your point. My response included an implicit rejection of
your point. :) I think it should be clear enough that in VBA a boolean


Sorry. I guess I didn't grasp that.
variable is False unless it has been set to True. I'm certainly not against
documenting what the purpose of a function is, but including a comment
that says 'the return value of this function is False unless it is set to
True'


Why? I prefer that intentions be made explicit -in- the code rather than
being discernable only via a combination of the code and a knowledge of the
behavior of the language.

Again, if the intenion is in no way made explicit, how can you be sure, on
re-reading the code, that an unhandled case is not simply overlooked rather
than having been explicitly ommitted because it is a default case?
Nov 12 '05 #18

P: n/a
Steve Jorgensen <no****@nospam.nospam> wrote in message news:<d5********************************@4ax.com>. ..
On Mon, 15 Sep 2003 21:30:06 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:cj********************************@4ax.com.. .
On Mon, 15 Sep 2003 17:22:05 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...
>
>BTW, in case cbfBoo = False was a typo, the default value of a
>boolean variable is false so setting it to false is redundant unless
>it was already set to true.

I think that's actually another case where relying on built-in
functionality can lead to unclear code. If you don't set the return value
to False for a particular case, is that because you knew the default would
be False, and that's what you wanted to return, or is it because you forgot to set the return value? Explicitly returning False makes it clear when
re-reading the code that you made a conscious decision to return False.


I my little world it would depend on what I was checking for in the
function.
If the function was most likely to return True and only a few criteria would
make it return False then I would set the return value to True at the top
and
set it to false if one of the criteria where met. The only reason I would
do
that is to eliminate using Not.

If YabaDabbaDoo then theFunction = False instead of
If Not YabbaDabbaDoo theFunction = True.


My point was that somewhere, you should make your intention clear that the
return value should be False if it was not set to True. You could do that
either with an explicit assignment before the remaining code, or as David
suggest, by including a comment expressing the intention.

Steve-

Have been following this thread with interest. You make some great
points. Nonetheless, have got to wonder if--having been slapped
upside the head with the fact that you didn't recognize Choose() and
Switch() as VBA functions--you're now attempting diligently to
backpedal your way out and cover your embarassment by showing that
these are really primitive functions with limited versatility. Got to
say it looks that way to me.

What do you think?

Imboden
Nov 12 '05 #19

P: n/a
On 15 Sep 2003 18:42:06 -0700, im*****@zalau.ro (Imboden) wrote:

....


Steve-

Have been following this thread with interest. You make some great
points. Nonetheless, have got to wonder if--having been slapped
upside the head with the fact that you didn't recognize Choose() and
Switch() as VBA functions--you're now attempting diligently to
backpedal your way out and cover your embarassment by showing that
these are really primitive functions with limited versatility. Got to
say it looks that way to me.

What do you think?

Imboden


Well, I'm always willing to second guess my motives in an argument, but I
think you've got the parties/opinions confused. I'm the one saying to keep
it simple until you need something complex. When I found out I was wrong
in thinking Choose was not a VBA function, I said it would be a -good- idea
to use it. It is David's point of view that it would be better to write a
more general-purpose function using Select Case early on without waiting
until there is an explicit requirement that demands it. Incidentally, I
think both David and I would suggest a table as an option since the major
usage in an Access app would probably be in queries and combo boxes.

I also don't believe (could be wrong - you never know) that I'm feeling any
hostility or anger toward the people I'm aguing with. In fact, I hold them
in the highest esteem. I hope the argument is useful to others trying to
decide whether to aim for more design up front or deferring more of it
until later. I'm not saying my opinion is more correct, just that it's my
opinion, and I can tell you why.
Nov 12 '05 #20

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:9k********************************@4ax.com...
Again, if the intenion is in no way made explicit, how can you be sure, on
re-reading the code, that an unhandled case is not simply overlooked rather than having been explicitly ommitted because it is a default case?


O.K. So a comment explaining that the most likely outcome of the function
will be to return False so it tests only for cases that would return True
may
not be so goofy.
Nov 12 '05 #21

P: n/a
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:
In other words, I think it's more important to spend more time
THINKING and less time CODING.


I think it's important to spend more time thinking about tables and
less time thinking about coding. (I'm expanding on what you said, not
disagreeing with it.)

--
Mike Sherrill
Information Management Systems
Nov 12 '05 #22

P: n/a
On Tue, 16 Sep 2003 09:20:50 -0500, Mike Sherrill
<MS*******@compuserve.com> wrote:
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:
In other words, I think it's more important to spend more time
THINKING and less time CODING.


I think it's important to spend more time thinking about tables and
less time thinking about coding. (I'm expanding on what you said, not
disagreeing with it.)


Perhaps, but if youre apps are like mine, the schema has mostly worked
itself out by abot 1/3 of the esy through the project, and was mostly
pretty simple. Not true in all apps, of course, but in most of the ones I
run into. After that, it's mainly about forms, reports, and code.
Nov 12 '05 #23

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<es********************************@4ax.com>:
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:

...

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).
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. . . .


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?
. . . 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.
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 indistinguishable 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*.
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.
If the basic structure is there already, you don't have to do
nearly as much reworking, as in the schema example above.
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!dlgAddPerson!txtFirstName & "', "
strValues = strValues & "'" & Forms!dlgAddPerson!txtLastName
_
& "'"
strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
strSQL = strSQL & " VALUES(" & strValues & ");"
dbCurrent.Execute 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.


Again, that's great, but why not wait until the first time that
abstraction is needed, then refactor. . . .


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.
. . . 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...
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.
With New clsPerson
.FirstName = ...: .LastName = ...
.SaveNew
... = .PersonID
End With
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.
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.


An what is that scope? How far ahead, and around how many
possible turns do you look? . . .


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.
. . . 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. . . .
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.
. . . 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?
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.
...
My point is that I believe it's important to consider the
architecture 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.
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.


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.
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
architecture 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.


I'm choosing to look at the big picture less up front. . . .


Yes, I know that, and I'm taking issue with your approach.
. . . 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.
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.
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.


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.
In other words, I think it's more important to spend more time
THINKING and less time CODING.


What about using coding as a tool for thinking. . . .


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.
. . . 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.


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
Nov 12 '05 #24

P: n/a
MS*******@compuserve.com (Mike Sherrill) wrote in
<tg********************************@4ax.com>:
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:
In other words, I think it's more important to spend more time
THINKING and less time CODING.


I think it's important to spend more time thinking about tables
and less time thinking about coding. (I'm expanding on what you
said, not disagreeing with it.)


Actually, you're contradicting me, as I think it's important to
think about the architecture of the code just as much as you think
about the architecture of the schema.

1. should this be in the current form's module or in a public
module? That is, will this code be used from anywhere other than
this particular form?

2. if it doesn't belong in the form module, which module should it
go in? It's own, or can it go in with some general public module
that's already there?

3. should I get data from the form itself, or use public variables
or pass parameters to the code?

4. is the task complex enough that it would benefit from being
wrapped in a class?

Obviously, if you have a command button to open the detail record
for a datasheet subform list, you don't need to consider all of
this. But if you're writing something reasonably complex, you need
to consider these things on the front end. And that doesn't even
get into the issue of what the architecture of the component itself
should be (i.e., how it's broken down into subroutines/functions,
etc.).

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #25

P: n/a
si******@besty.org.uk (Trevor Best) wrote in
<bh********************************@4ax.com>:
On Mon, 15 Sep 2003 20:40:57 GMT in comp.databases.ms-access,
dX********@bway.net (David W. Fenton) wrote:
Here, again, I disagree.
You would! :-)
A Boolean function will return false
unless you set it to something else. That's bloody obvious. An
integer or long will return 0. It shouldn't need to be made clear
to the person reading the code -- it should be clear from the
fact that it's a function of a particular type.

If you want to make it clear, then include a comment.

But include a specific setting to a value that does not need to
be set is bad practice, in my opinion, because it's a line of
code that is 100% unnecessary. If you're calling the thing in a
query 100K times, this might very well make a difference.

Comments are for clarifying.

Redundant lines of code can just as easily confuse the person
reading the code as clarify, as the person reading the function
might say "Wha? I must have misread this code, since I would have
thought the value would be FALSE already?" And then you waste
time walking back through the code trying to figure out why it
needed to be set to False.


But there's another argument, code portability. If you were to
port your function to an asp page for example, you would need that
bool=false line as there's no explicit datatypes in asp, without
it the function would return empty/nothing/whatever but not false.


I'm not going to do that, ever.

If you are, then include the line and comment it out, then
uncomment it when you convert to ASP. Or use conditional compiling,
if ASP supports that.

But I think code portability is not a very strong argument for
doing completely unnecessary operations.

And any language without explicit variable typing is trash, in my
opinion.
But yes, in VBA or VB if called 10000 times I would skip that
line.


How do you know that? Especially, if called from a query?

Either it would ignore the line regardless of how many times it is
called, or it would not. The number of calls can't make a
difference about whether or not the line is skipped.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #26

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<9k********************************@4ax.com>:
On Mon, 15 Sep 2003 23:36:10 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

...
My point was that somewhere, you should make your intention
clear that the return value should be False if it was not set
to True. You could do that either with an explicit assignment
before the remaining code, or as David suggest, by including a
comment expressing the intention.
I understood your point. My response included an implicit
rejection of your point. :) I think it should be clear enough
that in VBA a boolean


Sorry. I guess I didn't grasp that.
variable is False unless it has been set to True. I'm certainly
not against documenting what the purpose of a function is, but
including a comment that says 'the return value of this function
is False unless it is set to True'


Why? I prefer that intentions be made explicit -in- the code
rather than being discernable only via a combination of the code
and a knowledge of the behavior of the language.


If you don't know that basic fact, then you have no business coding
in the language.

You really do have to draw a line somewhere -- you can't go back to
Adam and Eve in every snippet of code that you write, just because
somewhere along the line someone who doesn't know VBA may end up
responsible for it.
Again, if the intenion is in no way made explicit, how can you be
sure, on re-reading the code, that an unhandled case is not simply
overlooked rather than having been explicitly ommitted because it
is a default case?


That's a logical issue and no amount of commenting or redundantly
setting the default value will make it clearer.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #27

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<92********************************@4ax.com>:
On 15 Sep 2003 18:42:06 -0700, im*****@zalau.ro (Imboden) wrote:
Have been following this thread with interest. You make some
great points. Nonetheless, have got to wonder if--having been
slapped upside the head with the fact that you didn't recognize
Choose() and Switch() as VBA functions--you're now attempting
diligently to backpedal your way out and cover your embarassment
by showing that these are really primitive functions with limited
versatility. Got to say it looks that way to me.

What do you think?
Well, I'm always willing to second guess my motives in an
argument, but I think you've got the parties/opinions confused.
I'm the one saying to keep it simple until you need something
complex. When I found out I was wrong in thinking Choose was not
a VBA function, I said it would be a -good- idea to use it. It is
David's point of view that it would be better to write a more
general-purpose function using Select Case early on without
waiting until there is an explicit requirement that demands it. .
.


No, Steve, I didn't say anything of the sort.

I said that if you could foresee the scope needing to encompass
something greater, then you would do that. And that was in the
context of your categorical rejection of CASE SELECT. I went to
some lengths to show that given an appropriate task, CASE SELECT
was by far the more efficient way to code the procedure.

And you agreed.
Incidentally, I think both David and I would suggest a table as an
option since the major usage in an Access app would probably be in
queries and combo boxes.
I don't know that *I* would suggest anything of the sort. The only
reason I'd suggest a table would be to make my generalized code
multi-lingual.

And I wouldn't assume at all that queries and combo boxes would be
the likely places for such a function to be used. I'd assume it
would be in reporting, and would be called in controls on the
report, not in queries at all.
I also don't believe (could be wrong - you never know) that I'm
feeling any hostility or anger toward the people I'm aguing with.
I don't see anything like that, either.
In fact, I hold them in the highest esteem. I hope the argument
is useful to others trying to decide whether to aim for more
design up front or deferring more of it until later. I'm not
saying my opinion is more correct, just that it's my opinion, and
I can tell you why.


The other point that may not be clear is that your point of view
here in this particular thread is quite consistent with various
arguments about coding style that you've been making on a regular
basis in this newsgroup over the last 6-9 months (or has it been a
year since you got religion? ;). Suggesting that your vehemence
comes from "embarassment" over the specifics of this thread hardly
explains the vigor with which we've argued these issues in many
previous threads touching on the subject of coding style.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #28

P: n/a
rkc

"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.86...
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!dlgAddPerson!txtFirstName & "', "
strValues = strValues & "'" & Forms!dlgAddPerson!txtLastName _
& "'"
strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
strSQL = strSQL & " VALUES(" & strValues & ");"
dbCurrent.Execute 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.


Seems to me the only parameter you would need to pass is the form object
that was used to gather the information. Re-use doesn't get any easier than
that.

Nov 12 '05 #29

P: n/a

On Tue, 16 Sep 2003 20:03:26 GMT, dX********@bway.net (David W.
Fenton) wrote in comp.databases.ms-access:
And any language without explicit variable typing is trash, in my
opinion.


Well, I don't disagree, but the issue here isn't explicit variable
typing but rather initialization of explicitly typed variables. And
automatic initialization within languages that *do* enforce explicit
typing is not (to me) a good indicator of whether such languages are
trash or not.

And to clarify, are you saying that any language that doesn't
*support* explicit variable typing is trash or that any language that
doesn't *require* explicit variable typing is trash? VBA, of course,
fails by the second standard.

Peter Miller
__________________________________________________ __________
PK Solutions -- Data Recovery for Microsoft Access/Jet/SQL
Free quotes, Guaranteed lowest prices and best results
www.pksolutions.com 1.800.987.7716 1.619.839.3900
Nov 12 '05 #30

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<es********************************@4ax.com>:
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:

...

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).
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. . . .


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?
. . . 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.
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 indistinguishable 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*.
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.
If the basic structure is there already, you don't have to do
nearly as much reworking, as in the schema example above.
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!dlgAddPerson!txtFirstName & "', "
strValues = strValues & "'" & Forms!dlgAddPerson!txtLastName
_
& "'"
strSQL = "INSERT (FirstName, LastName) INTO tblPerson"
strSQL = strSQL & " VALUES(" & strValues & ");"
dbCurrent.Execute 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.


Again, that's great, but why not wait until the first time that
abstraction is needed, then refactor. . . .


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.
. . . 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...
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.
With New clsPerson
.FirstName = ...: .LastName = ...
.SaveNew
... = .PersonID
End With
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.
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.


An what is that scope? How far ahead, and around how many
possible turns do you look? . . .


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.
. . . 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. . . .
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.
. . . 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?
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.
...
My point is that I believe it's important to consider the
architecture 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.
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.


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.
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
architecture 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.


I'm choosing to look at the big picture less up front. . . .


Yes, I know that, and I'm taking issue with your approach.
. . . 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.
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.
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.


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.
In other words, I think it's more important to spend more time
THINKING and less time CODING.


What about using coding as a tool for thinking. . . .


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.
. . . 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.


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
Nov 12 '05 #31

P: n/a
rkc

"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.90...
rk*@yabba.dabba.do.rochester.rr.com (rkc) wrote in
<1t********************@twister.nyroc.rr.com>:

Seems to me the only parameter you would need to pass is the form
object that was used to gather the information. Re-use doesn't
get any easier than that.


If the forms are identical and use the same controls, why, then,
would I worry about hardwiring the control references? The point is
that the source forms may not have the exact same fields and the
particular person being added may not require the exact same data
to create the record.


If the data collected by the forms is different and the entities being
dealt with are different, why, then, would you want to build one
convoluted method to deal with all of them?
If you pass a form reference, the logic for determining which
controls to process has to be in your AddPerson subroutine.


Why is that bad? If you write a function to do a task for you,
why burden the calling code with having to go on and on about
what it wants the function to do?

Nov 12 '05 #32

P: n/a
On Tue, 16 Sep 2003 20:03:26 GMT in comp.databases.ms-access,
dX********@bway.net (David W. Fenton) wrote:
But yes, in VBA or VB if called 10000 times I would skip that
line.


How do you know that? Especially, if called from a query?

Either it would ignore the line regardless of how many times it is
called, or it would not. The number of calls can't make a
difference about whether or not the line is skipped.


What I mean is if I knew the function would be called from a query or
a loop, I'd comment it out or not put it in there in the first place.

--
A)bort, R)etry, I)nfluence with large hammer.

(replace sithlord with trevor for email)
Nov 12 '05 #33

P: n/a
On Tue, 16 Sep 2003 20:03:26 GMT in comp.databases.ms-access,
dX********@bway.net (David W. Fenton) wrote:
And any language without explicit variable typing is trash, in my
opinion.


I used to think ASP was crap because just about every asp page I
visited asked me to debug it, since writing my own I have found it
wasn't the language that was crap, the ones I release don't ask the
user to debug them for me, I've done that before releasing it.

VBScript is crap compared to VB and VBA, not nearly as functional, I
can't roll a cigarette as well as a tailor made but as it says on my
pouch of Drum "It's in your hands".

--
A)bort, R)etry, I)nfluence with large hammer.

(replace sithlord with trevor for email)
Nov 12 '05 #34

P: n/a
rk*@yabba.dabba.do.rochester.rr.com (rkc) wrote in
<F8********************@twister.nyroc.rr.com>:
"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.90...
rk*@yabba.dabba.do.rochester.rr.com (rkc) wrote in
<1t********************@twister.nyroc.rr.com>:

>Seems to me the only parameter you would need to pass is the
>form object that was used to gather the information. Re-use
>doesn't get any easier than that.


If the forms are identical and use the same controls, why, then,
would I worry about hardwiring the control references? The point
is that the source forms may not have the exact same fields and
the particular person being added may not require the exact same
data to create the record.


If the data collected by the forms is different and the entities
being dealt with are different, why, then, would you want to build
one convoluted method to deal with all of them?


I'm adding records to the Person table. Some of the records are
students, some are parents. Students require a SchoolID to be
inserted, parents don't. Otherwise, they function exactly the same.
Why have two different forms that would differ so little?
If you pass a form reference, the logic for determining which
controls to process has to be in your AddPerson subroutine.


Why is that bad? If you write a function to do a task for you,
why burden the calling code with having to go on and on about
what it wants the function to do?


I like to push rather than pull. That is, I think that the place
where the smarts should be is closer to the context in which the
act is initiated. So, in the code behind the command button it
seems to me to be the proper place for setting things up so the
code you're calling can get things done, without needing to be told
what to do.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #35

P: n/a
pm*****@pksolutions.com (Peter Miller) wrote in
<c5********************************@4ax.com>:

On Tue, 16 Sep 2003 20:03:26 GMT, dX********@bway.net (David W.
Fenton) wrote in comp.databases.ms-access:
And any language without explicit variable typing is trash, in my
opinion.
Well, I don't disagree, but the issue here isn't explicit variable
typing but rather initialization of explicitly typed variables.
And automatic initialization within languages that *do* enforce
explicit typing is not (to me) a good indicator of whether such
languages are trash or not.


Yes, that is a difference, and I guess I made an erroneous
statement.
And to clarify, are you saying that any language that doesn't
*support* explicit variable typing is trash or that any language
that doesn't *require* explicit variable typing is trash? VBA, of
course, fails by the second standard.


Anyone who uses VBA without utilizing the narrowest possible data
types is an idiot.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #36

P: n/a
si******@besty.org.uk (Trevor Best) wrote in
<mo********************************@4ax.com>:
On Tue, 16 Sep 2003 20:03:26 GMT in comp.databases.ms-access,
dX********@bway.net (David W. Fenton) wrote:
And any language without explicit variable typing is trash, in my
opinion.


I used to think ASP was crap because just about every asp page I
visited asked me to debug it, since writing my own I have found it
wasn't the language that was crap, the ones I release don't ask
the user to debug them for me, I've done that before releasing it.

VBScript is crap compared to VB and VBA, not nearly as functional,
I can't roll a cigarette as well as a tailor made but as it says
on my pouch of Drum "It's in your hands".


I just don't see any use for VBScript, myself, since it's not
cross-platform compatible.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #37

P: n/a

On Wed, 17 Sep 2003 03:28:29 GMT, dX********@bway.net (David W.
Fenton) wrote in comp.databases.ms-access:
Anyone who uses VBA without utilizing the narrowest possible data
types is an idiot.


<chuckle>

You mean there's actually people who don't start every code module
with 'Option Explicit'? Say it ain't so!

Peter Miller
__________________________________________________ __________
PK Solutions -- Data Recovery for Microsoft Access/Jet/SQL
Free quotes, Guaranteed lowest prices and best results
www.pksolutions.com 1.800.987.7716 1.619.839.3900
Nov 12 '05 #38

P: n/a
On Wed, 17 Sep 2003 03:28:29 GMT, dX********@bway.net (David W. Fenton)
wrote:
pm*****@pksolutions.com (Peter Miller) wrote in
<c5********************************@4ax.com>:

On Tue, 16 Sep 2003 20:03:26 GMT, dX********@bway.net (David W.
Fenton) wrote in comp.databases.ms-access:
And any language without explicit variable typing is trash, in my
opinion.


Well, I don't disagree, but the issue here isn't explicit variable
typing but rather initialization of explicitly typed variables.
And automatic initialization within languages that *do* enforce
explicit typing is not (to me) a good indicator of whether such
languages are trash or not.


Yes, that is a difference, and I guess I made an erroneous
statement.
And to clarify, are you saying that any language that doesn't
*support* explicit variable typing is trash or that any language
that doesn't *require* explicit variable typing is trash? VBA, of
course, fails by the second standard.


Anyone who uses VBA without utilizing the narrowest possible data
types is an idiot.


I mostly agree. When It comes to choosing a refactoring that removes alot
of duplication vs preserving type safety, though, it's a hard choice, and
I'll often favore the refactoring. Here, automated tests of the code (when
easy to implement - it often is) can make up for the lack of compile-time
checking.

Also, I know you know about the problems of early binding to OLE and
ActiveX libraries, so no need to rehash that exception. I found a new
trick, though, for doing early binding during development and switching to
late binding for deployment that's really cool. Wrap the reference in a
user-defined type, and change the type declaration from <whatever> to
Object at deployment time. Also write a function to create a new object
with one line commented out depending on development/deployment. Either
returns New <object-type> or CreateObject(...). Only 2 lines of code to
change for each type in the whole project.
Nov 12 '05 #39

P: n/a
On Wed, 17 Sep 2003 03:48:34 GMT in comp.databases.ms-access, Peter
Miller <pm*****@pksolutions.com> wrote:
<chuckle>

You mean there's actually people who don't start every code module
with 'Option Explicit'? Say it ain't so!


Ohhhhhhh yes. Didn't NASA once lose a (IIRC unmanned) rocket because a
Fortran program had an undeclared variable and it defaulted to the
wrong type?

--
A)bort, R)etry, I)nfluence with large hammer.

(replace sithlord with trevor for email)
Nov 12 '05 #40

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<v8********************************@4ax.com>:
On Tue, 16 Sep 2003 19:52:54 GMT, dX********@bway.net (David W.
Fenton) wrote:

...
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. . . .
What if you are pretty damned sure the second case will arise?


If that's so, one could force the issue by choosing the next
function to implement to be one that's likely to need the second
case.
What if it doesn't take any more work to code for the second case
than it does to code for the first?


I think that's a limited subset.

Another point is that, while I'm suggesting to wait on writing
code to handle cases that do not yet exist. . .


Here's a fundamental problem of this discussion: I'm not talking
about writing *code* that isn't yet needed. I'm talking about
designing of the architecture of the code you *do* need right now
so that it is flexible enough to handle what you *may* need later.

That's a really big difference.
. . . and actually avoiding
thinking about doing so while making the code initially run, I do
advocate eliminating code smells before delivering the code so
long as this assessment is derived prior to worrying much about
outside requirements. Much of this clean-up will, incidentally
help in terms of code reusability. Some smells are - duplication
within the code, duplication with other code, code that's not
stratightforward to read, functions that are excessively large,
functions that are excessively small (sometimes), passing too many
parameters between functions, etc.

Code outside of the code directly written to accomplish the task
also gets cleaned and generalized at this point (possibly
somtheing that was -not- generalized an hour ago because the
requirement wasn't there). This often happens when you see soo
much data being passed between functions and realize that
something in the new code should actually be moved into a
previously existing function where the items it most relates to
are normally handled.

Once the code is clean, it should be clear that it will be easy to
change and extend without having to explicitly account for
specific cases now, though some of those will have been
incidentally handled by simply making the code clean.

In a way, I think we're saying nearly the same thing, but with
different emphasis and in different order. I say make the code
work even if it's the damndest hack, then immediately clean it,
but dealing only with the requirements needed so far. Get the
code clean enough that there is no fear of being able to make it
more general, but don't worry about whether it actually -is- more
general as it stands.
I would go the additional step, that you should choose a design
that allows for the later expansion, when there's a clear choice
and when the time to implement the more flexible architecture is
not excessive.
. . . 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.


I think it's easier to choose an architecture that has no
unnecessary dependencies on the specifics of its initial
implementation.


Have you tried the refactoring route? I can't guarantee you'll
appreciate it as I do, but it's worth a try. Basically, in
refactoring stages, only code changes that should have -zero-
effect on the actual functioning of the code (outside of some
execution speed effect) are done, and mostly with an eye on
reducing the amount and complexity of code. The stages of adding
functionality and refactoring should -not- be mixed. I find that
the process of separating coding from refactoring reduces the
anxiety involved in programming and allows for greater speed.


Yes, I do understand that. And I've done it extensively with older
projects that took on new life. And last night late I was doing
some quick coding to fix up some things I forgot needed to be done
for a client meeting today, and several times thought "well, here
I'm going to pull a Steve." :)
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.


Here's a case where I'd have to agree with your point of view, and
I agree basically because it's hard to refactor forms and reports.


Most of my coding involves very close interaction with forms and
reports, so I don't see how you can separate coding from the
process of UI design. Indeed, 90% of the work I do in Access is UI
design, and that involves forms/reports embedded in code, and code
embedded in the forms/reports.

It doesn't seem like something separate to me at all.
I consider this to be one of the biggest down sides of Access
because I would like to apply the same process I apply to code to
everything else in the app - but I don't because it doesn't work.
I don't see that the code is that separate. I don't write
algorithms that are self-contained, I write code that encapsulates
processes that require interaction with human beings, which of
necessity is UI design.
Even here, though, I try not to go overboard, and addresses are a
good example of where this can happen (not your example here, but
addresses for sure). I've seen dozens of apps over the years (3
of them were mine) in which the contact management portion of the
application was overdesigned because the true nature of its
eventual use was not understood up front, so every imagined
possibility was accounted for. In every case, the code to handle
it was way out of hand (up to 1/3 of the project - not primarily a
contact management app). After all of that, there usually turned
out to be somthing important that was -not- accounted for, and was
scary to add because the structures were complex ansd difficult to
modify without breaking something. I see, farther down, you do
agree on this point, so I guess I'm preaching to the choir (still,
for any onlookers).
I agree with you that you can go overboard. And the only way to
know the difference between "perfect schema" and "gone overboard"
is experience. I've developed a feel for when it makes sense to
have an elaborate schema and when it's better to do something in a
simpler way.

I think designing your code has the same benefits from experience.
Certain kinds of activities you do on a regular basis and know how
to accomplish them, so you don't really have to think about it.
It's mostly when things inter-relate that you have to worry about
architecture, and when you have multiple points of entry into
subroutines.

Say you have a subroutine with a flag parameter that you are using
to skip whole huge swaths of the subroutine. That's a case where
there's a major architectural problem -- the optional code ought to
be in its own subroutine.

And that's precisely what I'm talking about in terms of
architecture.

This kind of thing often happens when you encounter a special case.
But the question is: handle the special case inline or hand off the
special case to a subroutine? I'd immediately choose the latter, as
long as the subroutine didn't need a gazillion local variable
values and would therefore require 2 dozen parameters to be passed
to it.

Of course, once the code is written and works, then it's a
candidate for refactoring, but it would be well down my priority
list.
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.


Agreed on this point. Again, I might would not agree if this
were, say, a Java front-end. And granted, we are not talking
about Java front-ends.


I don't see why that would matter. Java is not doing the data
retrieval, so why would it matter how the stuff is stored?
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.


On the schema, I cautiously of agree, . . .


For me, though, I keep encountering variations on the same basic
schemas, since all of my apps tend to be built around the same
kinds of entities. I then have certain principles that I use for
designing UI components around those entities. So, my choices are
usually between a number of alternatives that I'm already familiar
with and I make the decision of incorporation of flexible design
principles based on my estimation of the benefit to be gained for
the particular application at hand.
. . . though it's very easy to
overestimate what's forseeable, and almost anything will
eventually have to be changed in a big app. It often makes sense
to make a prototype schema, get the users to enter as much sample
data as you can coerce them into entering for you (with clear
communication that this is for prototyping only!), then start
designing the new schema by looking at the relationships that
actually appear in the sample data, not the ones evident in the
specs. Of course, this is made vastly easier if there is a
previous application being replaced, and the old data already
exists in digital form.
I have one app that I really regret the schema I created. It seemed
an obvious thing to do, using a supertype table and multiple
subtype tables, but it's turned out to be a nightmare in the end.
Possibly I didn't think through the design so that I properly
designed my class modules for it, but somewhere along the line,
things are just not working, and I have one helluva time keeping
the code working reliably.

And I've refactored that code twice already!

Given that, I think the flaw must be in the underlying schema -- I
tried to do too many things in a multi-purpose way and failed to do
any of the individual things particularly well.
...
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*.
But you are also talking about the parts of the app that impact
the structures hardest to change later. I guess I agree with you
in these cases, and these cases are a large portion of an Access
database app. On the parts of the app that are more code-bound,
though, I aim for implementing only single requirements at a time.


As I said before, my code is intimately tied up with the schema and
the forms/reports, so I don't see any bright line distinction
between code and the rest.
There's a grey area, but I try to push it as far forward as I can
before the effort required to refactor is requiring excessive
cleverness and starts making the code less clear instead of more
so.
I'm not saying you should waste an hour thinking about it. I'm
saying that you should spend couple of minutes considering the
architecture of the code you're about to write.
...
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.

Again, that's great, but why not wait until the first time that
abstraction is needed, then refactor. . . .
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.


Yes, it's encapsulation. One thing highly dependent upon
something else. I guess my pooint of view (reiterating from above)
is that, if there's any fear that the code will be hard to
refactor, then indeed it is not done. So, yes, immediatley make
the code more clear in the quicked, easiest way possible (even if
it is not what obviously fixes the encapsulation) until there is
no fear of needing to take time to get your head back into it.
Some of that may, in fact, either improve the encapsulation, or
merely make it more obvious how one would remove the encapsulation
when needed.


I'm not sure I'd call that "encapsulation." I'd call it
"generalization." Well, I guess you're right, it's something of
both.
. . . 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...


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.


So, would it not be fresh in your head? You thought you would
need it right away, and you did. If it had turned out not to be
needed for a longer time, enough things might have changed around
it that your previous freshness with the code might be of no use.


In this case, as I was revising someone else's code, it might have
saved time had I not needed it and left it as it came to me. But I
was 80% sure I was going to need the generalization when I did it,
even though it was some hours after I generalized the code before I
came on the definitive answer as to whether I was going to need it
or not.

This was one of those experience situations -- my gut knew I was
going to need it. I've learned to trust my gut on these things,
because it's when I've ignored it that I got in trouble!
With New clsPerson
.FirstName = ...: .LastName = ...
.SaveNew
... = .PersonID
End With


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 agree that classes are heayweight solutions in Access, but I'm
using them more and more because they turn out to be one of the
best ways to remove code duplication. . . .


I use them a lot, too, though quite often as nothing more than a
self-healing data structure that is used to avoid globals.
. . . They becaume much more
useful to me when I stopped thinking of them as only being useful
in cases where the state needed to be maintained for a long period
(see, I have an object expiring at the end of its With block!). I
think an entity type that warrants a table or more warrants a
class. Then common code can even be refactored into another
"parent" class that each entity class holds an instance of.
Well, I don't go that far with classes in Access because you really
can't do inheritance, so that level of abstraction just doesn't
seem to work.
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.


Well, me either until there are enough use cases to justify it
(clearly <g>).


But, Steve, you'd never create your Person class, because you'd
never be able to justify all that work for no purpose, no? ;)
...
so that the code you write performs well in the scope for which
it is conceived.

And what is that scope? How far ahead, and around how many
possible turns do you look? . . .
I'm not recommending spending 8 hours thinking about all the
possibilities. I'm suggesting using your experience, as in the


Yes, I do see that.


This is all about leveraging experience, I think, more than it's
about coding practices.
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.


Well, in the case of schema for an Access app, I might even
concede the point where it does increase the amount of work to get
the job done, but to a limited degree (preferably with at least
one milesone, and a deadline). . . .


Does it really take longer to create a separate table and create
the 1:1 relationship? Maybe 2 minutes? In terms of designing the
UI, adding the Address table and changing the join type. What, 30
seconds?

Gee, we've used up and entire 150 seconds!!!!!!
. . . And again, I concede this point
only because our tool is limited in its ability to allow easy
refactoring of form designs (though I'm getting better at it).
Even if form designs were more easily changed, I'd think it would
still be a superior design, not because it saves so much time, but
because it is just a more flexible design in the first place.
Speaking of deadlines, I have other stuff I have to get to, but
I'll try to respond to the remaining points within the following
days.


Well, aside from me dwelling on experience, I'm not really adding
much new at this point!

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #41

P: n/a
rkc

"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.90...
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.


When the client decides that they do after all want to be able to
associate more than one address per person, having previously
rejected your advice that they most likely would, how do you
charge them? Do you charge them as though you hadn't made
the decision to think ahead? Do you charge them for the time it
would have taken you to change the schema and re-work the
forms you already had built? Do you reward yourself for your
past experience or do you reward your client for hiring you?




Nov 12 '05 #42

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:v8********************************@4ax.com...
On Tue, 16 Sep 2003 19:52:54 GMT, dX********@bway.net (David W. Fenton)
wrote:
<major snip>
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.


Yes, it's encapsulation. One thing highly dependent upon something else.

for this application -- a definite case where that would be work
that was not necessary to get the thing working well.


Forgive me, I am going to yap at you because D.W.'s mind is set in
concrete.

Everything has to depend on something. A form is a GUI object that
facilitates the collection of data from an outside source. If it's purpose
is to collect data about a person then the value's entered into the form's
controls are in fact the properties that make up that person entity. Why
then should a sub-routine (or better yet a class) that is built to deal with
that person entity, say a SavePerson class, not know about the properties
of the object that collects the information? The form is nothing more than
a CollectPersonInformation object. Why even consider a Person object
when what is needed is a SavePerson object that knows everything it
needs to know about the CollectPersonInformation object.
I agree that classes are heayweight solutions in Access, but I'm using them more and more because they turn out to be one of the best ways to remove
code duplication.


I don't understand the sprinkled use of class objects because they are
'heavyweight solutions'.

Since VBA does not support inheritance, the best way to remove code
duplication is to create objects that serve a specific purpose and use them
in other objects that need that functionality via containment.


Nov 12 '05 #43

P: n/a
I'll add a caveat -- if you don't get the tables/schema design right, no
amount of excellence in the structure of the application is going to save
your tail. Hey, we are talking about _database_ applications.

And, you know, most of the applications I've worked on in all my
incarnations (mainframer, minicomputer guy, and micro manipulator) turned
out to be data-based, even if they didn't use a "database". Structure your
data wrong and the application was going to be a mess.

Larry Linson

"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.90...
MS*******@compuserve.com (Mike Sherrill) wrote in
<tg********************************@4ax.com>:
On Mon, 15 Sep 2003 20:33:00 GMT, dX********@bway.net (David W.
Fenton) wrote:
In other words, I think it's more important to spend more time
THINKING and less time CODING.


I think it's important to spend more time thinking about tables
and less time thinking about coding. (I'm expanding on what you
said, not disagreeing with it.)


Actually, you're contradicting me, as I think it's important to
think about the architecture of the code just as much as you think
about the architecture of the schema.

1. should this be in the current form's module or in a public
module? That is, will this code be used from anywhere other than
this particular form?

2. if it doesn't belong in the form module, which module should it
go in? It's own, or can it go in with some general public module
that's already there?

3. should I get data from the form itself, or use public variables
or pass parameters to the code?

4. is the task complex enough that it would benefit from being
wrapped in a class?

Obviously, if you have a command button to open the detail record
for a datasheet subform list, you don't need to consider all of
this. But if you're writing something reasonably complex, you need
to consider these things on the front end. And that doesn't even
get into the issue of what the architecture of the component itself
should be (i.e., how it's broken down into subroutines/functions,
etc.).

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc

Nov 12 '05 #44

P: n/a
Why, I heard there was a large contingent demanding an "Option Implicit".
Hadn't you heard about that movement? <G>

"Peter Miller" <pm*****@pksolutions.com> wrote in message
news:0s********************************@4ax.com...

On Wed, 17 Sep 2003 03:28:29 GMT, dX********@bway.net (David W.
Fenton) wrote in comp.databases.ms-access:
Anyone who uses VBA without utilizing the narrowest possible data
types is an idiot.


<chuckle>

You mean there's actually people who don't start every code module
with 'Option Explicit'? Say it ain't so!

Peter Miller
__________________________________________________ __________
PK Solutions -- Data Recovery for Microsoft Access/Jet/SQL
Free quotes, Guaranteed lowest prices and best results
www.pksolutions.com 1.800.987.7716 1.619.839.3900

Nov 12 '05 #45

P: n/a
On Wed, 17 Sep 2003 18:32:28 GMT, dX********@bway.net (David W. Fenton)
wrote:

....
Here's a fundamental problem of this discussion: I'm not talking
about writing *code* that isn't yet needed. I'm talking about
designing of the architecture of the code you *do* need right now
so that it is flexible enough to handle what you *may* need later.

That's a really big difference.
In doing this, you are predicting what you do need later (coding for a
-future- requirement), and you're banking on the fact that what you're
going to need later -first- would not be better accomplished after
implementing some other code change that will be needed sooner, and that
you cannot yet be aware of.

....
In a way, I think we're saying nearly the same thing, but with
different emphasis and in different order. I say make the code
work even if it's the damndest hack, then immediately clean it,
but dealing only with the requirements needed so far. Get the
code clean enough that there is no fear of being able to make it
more general, but don't worry about whether it actually -is- more
general as it stands.


I would go the additional step, that you should choose a design
that allows for the later expansion, when there's a clear choice
and when the time to implement the more flexible architecture is
not excessive.


Perhaps, we are simply using different meanings of "allows for later
expansion." I would say that once the code is clean, and clear, and well
organized, it can be easily modified for future expansion even if it is not
currently pluggable for multiple cases. Once the code is at a point where
there is no anxiety about it being easy to change, it no longer feels
necessary to, up front, actually make it more general than necessary for
already implemented requriements. This code can now easily move in
directions that are not expected as well as those that are. In fact, in
making the code simple, duplication with other code in the project may
become visible that was not obvious before hand.

....
Have you tried the refactoring route? I can't guarantee you'll ....Yes, I do understand that. And I've done it extensively with older
projects that took on new life. And last night late I was doing
some quick coding to fix up some things I forgot needed to be done
for a client meeting today, and several times thought "well, here
I'm going to pull a Steve." :)
Refactoring doesn't just have to be for old code that has become messy,
though. It can be an integral part of a development process so that, if at
any point, the project has to be dropped for 2 weeks, the existing code is
as clear and concise as it can be for what it does so far.
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.


Here's a case where I'd have to agree with your point of view, and
I agree basically because it's hard to refactor forms and reports.


Most of my coding involves very close interaction with forms and
reports, so I don't see how you can separate coding from the
process of UI design. Indeed, 90% of the work I do in Access is UI
design, and that involves forms/reports embedded in code, and code
embedded in the forms/reports.

It doesn't seem like something separate to me at all.


The relation between the Access UI and the schema is very different from
the relation between code and the UI or between code and the schema. I
presume you would agree. While we are both agreeing that code can be made
somewhat general in terms of the forms and tables it works with (just
aguing about when), changes to the schema can easily break bound forms, and
there's no compiler to catch the problem, so it only turns up either in
your memory or in testing.

Implementing a 1-to-many relationship, there must be some representation of
this on the form, usually a master/subform construct or something. This is
very different from refactoring (or implementing up-front) something along
the lines of a procedure that tries to invoke a GetEntityName method for an
arbitrary Form object, and adding the appropriate method code to each form.
In Access 2000 and above, you can even have each Form module Implement an
interface, so the compiler can validate the code.
I consider this to be one of the biggest down sides of Access
because I would like to apply the same process I apply to code to
everything else in the app - but I don't because it doesn't work.


I don't see that the code is that separate. I don't write
algorithms that are self-contained, I write code that encapsulates
processes that require interaction with human beings, which of
necessity is UI design.


But you said yourself that it's better for the code to be flexible in terms
of what forms it can work with. Access forms are generally not very
agnostic in terms of what schema they will work with, though one can design
the schema to be general enough to increase the scope a single form will be
able to cover. Again, here's where schemas and form layouts are much
harder to change later than code is.

....I think designing your code has the same benefits from experience.
Certain kinds of activities you do on a regular basis and know how
to accomplish them, so you don't really have to think about it.
It's mostly when things inter-relate that you have to worry about
architecture, and when you have multiple points of entry into
subroutines.
And we agree on this point. I think we are only disagreeing on -when- to
make the code more general.
Say you have a subroutine with a flag parameter that you are using
to skip whole huge swaths of the subroutine. That's a case where
there's a major architectural problem -- the optional code ought to
be in its own subroutine.
And I would definitely do this up front because it makes the current code
more clear. Anything that makes the code more clear is fair game for that
reason alone, and if it helps reusability as a side benefit, that's cool
too.
And that's precisely what I'm talking about in terms of
architecture.
That's why I'm saying out mechanical procedures probably don't differ much,
but I think changing the thought priorities has been very helpful to me.
Why clean this code? Because it's messy. If it's clean, but doesn't
handle every case I think it should eventually be able to do, I leave it
alone even if I think it's easy. Why?

1. There's a finite chance that I'm wrong about it being easy, and once I
start, I won't want to let it go.
2. There's a finite chance that something will come along before the other
case is needed that the extra code I wrote simply makes harder to figure
out how to factor in (cart before the horse - sofa in the room before I
know where it's going).
This kind of thing often happens when you encounter a special case.
But the question is: handle the special case inline or hand off the
special case to a subroutine? I'd immediately choose the latter, as
long as the subroutine didn't need a gazillion local variable
values and would therefore require 2 dozen parameters to be passed
to it.
As above, I agree if the code is more clear with this change.
Of course, once the code is written and works, then it's a
candidate for refactoring, but it would be well down my priority
list.
That used to be how I felt, but this is what is known as a technical debt.
If you have code that was not made as clear as it could be when you were
clear on how it worked, yuo have just cost yourself extra time the next
time you have to work with it. This cost will be incurred each time you
revisit the code. It costs with interest. Also, the refactored code may
expose options for later resues that were not otherwise evident.

....
Agreed on this point. Again, I might would not agree if this
were, say, a Java front-end. And granted, we are not talking
about Java front-ends.


I don't see why that would matter. Java is not doing the data
retrieval, so why would it matter how the stuff is stored?


Well, if I was using a tool that was not based around rapid development by
basing a GUI on a schema, I would probably have a looser coupling between
the 2 with code in between. probably something like an MVC pattern.
Changes to the schema would not direclty impact the GUI, and the impact on
the code would become more and more limited as the code evolved to become
better encapsulated.

....
. . . though it's very easy to
overestimate what's forseeable, and almost anything will
eventually have to be changed in a big app. It often makes sense
to make a prototype schema, get the users to enter as much sample
data as you can coerce them into entering for you (with clear
communication that this is for prototyping only!), then start
designing the new schema by looking at the relationships that
actually appear in the sample data, not the ones evident in the
specs. Of course, this is made vastly easier if there is a
previous application being replaced, and the old data already
exists in digital form.


I have one app that I really regret the schema I created. It seemed
an obvious thing to do, using a supertype table and multiple
subtype tables, but it's turned out to be a nightmare in the end.
Possibly I didn't think through the design so that I properly
designed my class modules for it, but somewhere along the line,
things are just not working, and I have one helluva time keeping
the code working reliably.

And I've refactored that code twice already!


That's definitely one you only learn by doing it wrong, eh? I tried
something similar with similarly awful results. I'm still not even sure
-why- it comes out so awful.

....
....But, Steve, you'd never create your Person class, because you'd
never be able to justify all that work for no purpose, no? ;)


It would be jsutifies as soon as I had the second or third use case. I
would refactor the code, and move most of it to the class module.

Nov 12 '05 #46

P: n/a
rk*@yabba.dabba.do.rochester.rr.com (rkc) wrote in <I57ab.107181
$7********@twister.nyroc.rr.com>:

"David W. Fenton" <dX********@bway.net> wrote in message
news:93*********************@24.168.128.90...
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 hadvery little work to change the relationship to 1:N. You might thinkthat 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 yourform. When you convert to 1:N, then you have to change the
recordsource to take out the join to the address table and create asubform 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.


When the client decides that they do after all want to be able to
associate more than one address per person, having previously
rejected your advice that they most likely would, how do you
charge them? Do you charge them as though you hadn't made
the decision to think ahead? Do you charge them for the time it
would have taken you to change the schema and re-work the
forms you already had built? Do you reward yourself for your
past experience or do you reward your client for hiring you?


I would use it for propaganda purposes, telling them that I planned
for the extension and therefore, saved them money in the long run.
And add in a big dose of "I told you so" and stress that it won't
always be possible for me to plan around their mistakes in a way
that doesn't cost them a lot of money.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #47

P: n/a
rk*@yabba.dabba.do.rochester.rr.com (rkc) wrote in
<A_********************@twister.nyroc.rr.com>:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:v8********************************@4ax.com.. .
On Tue, 16 Sep 2003 19:52:54 GMT, dX********@bway.net (David W.
Fenton) wrote:


<major snip>
>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.


Yes, it's encapsulation. One thing highly dependent upon
something else.

>for this application -- a definite case where that would be
>work that was not necessary to get the thing working well.
Forgive me, I am going to yap at you because D.W.'s mind is set in
concrete.

Everything has to depend on something. A form is a GUI object
that facilitates the collection of data from an outside source. If
it's purpose is to collect data about a person then the value's
entered into the form's controls are in fact the properties that
make up that person entity. Why then should a sub-routine (or
better yet a class) that is built to deal with that person entity,
say a SavePerson class, not know about the properties of the
object that collects the information? The form is nothing more
than a CollectPersonInformation object. Why even consider a
Person object when what is needed is a SavePerson object that
knows everything it needs to know about the
CollectPersonInformation object.


The point is that I may have more than one object from which the
SavePerson class is driven. Therefore, the SavePerson class should
have no dependencies on any particular object that collects the
information to drive the SavePerson class.
I agree that classes are heayweight solutions in Access, but I'm
using

them
more and more because they turn out to be one of the best ways
to remove code duplication.


I don't understand the sprinkled use of class objects because they
are 'heavyweight solutions'.

Since VBA does not support inheritance, the best way to remove
code duplication is to create objects that serve a specific
purpose and use them in other objects that need that functionality
via containment.


My final implementation ended up being based on a single form that
is dynamically changed when loaded, according to which type of
Person is being added. This means that the AddPerson subroutine
could have retained its dependency on the form dlgAddPerson without
breaking. However, by removing that dependency, I left myself the
*option* of adding a person from more than one location. Indeed,
after meeting with the client yesterday, it became pretty clear
that I am likely to need to create a more elaborate dialog for
adding a person because there is a less specific context in which
I'll be adding people than the two contexts I've already
implemented.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #48

P: n/a
no****@nospam.nospam (Steve Jorgensen) wrote in
<lq********************************@4ax.com>:
On Wed, 17 Sep 2003 18:32:28 GMT, dX********@bway.net (David W.
Fenton) wrote:

...
Here's a fundamental problem of this discussion: I'm not talking
about writing *code* that isn't yet needed. I'm talking about
designing of the architecture of the code you *do* need right now
so that it is flexible enough to handle what you *may* need
later.

That's a really big difference.
In doing this, you are predicting what you do need later (coding
for a -future- requirement), . . .


Only in part. The point is not so much creating structure that will
handle everything so much as avoiding creating structure that can
definitely *not* handle any eventualities *except* the ones that
are already known.
. . . and you're banking on the fact that
what you're going to need later -first- would not be better
accomplished after implementing some other code change that will
be needed sooner, and that you cannot yet be aware of.
If you know the code you're writing is intimately and irrevocably
tied to the circumstances for which it was created and you have
rejected simple structural changes that could make it more
flexible, then I think you're making a mistake.
...
In a way, I think we're saying nearly the same thing, but with
different emphasis and in different order. I say make the code
work even if it's the damndest hack, then immediately clean it,
but dealing only with the requirements needed so far. Get the
code clean enough that there is no fear of being able to make it
more general, but don't worry about whether it actually -is-
more general as it stands.
I would go the additional step, that you should choose a design
that allows for the later expansion, when there's a clear choice
and when the time to implement the more flexible architecture is
not excessive.


Perhaps, we are simply using different meanings of "allows for
later expansion." I would say that once the code is clean, and
clear, and well organized, it can be easily modified for future
expansion even if it is not currently pluggable for multiple
cases. . .


I'm actually talking about things that are substantially more
basic:

1. where do you put the code, in a form/report module or in a
standalone module?

2. how do you structure the code, in a single monolothic subroutine
or in small bits that can call each other, some of which can be
used independent of the current context?

Those are the two big questions I'm speaking about when I talk
about code structure.
. . . Once the code is at a point where there is no anxiety
about it being easy to change, it no longer feels necessary to, up
front, actually make it more general than necessary for already
implemented requriements. This code can now easily move in
directions that are not expected as well as those that are. In
fact, in making the code simple, duplication with other code in
the project may become visible that was not obvious before hand.
I definitely try to avoid *any* code duplication of more than a few
lines. For instance, I wouldn't create a sub to open a form if the
code I'm using for that is only a couple of lines. But if I'm doing
some complicated things to set up the form before making it
visible, or using the "semi-bound" approach where the recordsource
is assigned after opening, then I'd probably write a subroutine or
function for opening the form.

And I'd do that the first time I realized that it was likely that I
was going to need to open the form from more than one context, even
if I hadn't yet implemented the second context yet.
...
Have you tried the refactoring route? I can't guarantee you'll...
Yes, I do understand that. And I've done it extensively with
older projects that took on new life. And last night late I was
doing some quick coding to fix up some things I forgot needed to
be done for a client meeting today, and several times thought
"well, here I'm going to pull a Steve." :)
Refactoring doesn't just have to be for old code that has become
messy, though. It can be an integral part of a development
process so that, if at any point, the project has to be dropped
for 2 weeks, the existing code is as clear and concise as it can
be for what it does so far.


That's a good goal, and really I don't see it that different from
what I'm doing, since I choose my structures on the front end to
try to get it closer to a state where it is clear.
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.

Here's a case where I'd have to agree with your point of view,
and I agree basically because it's hard to refactor forms and
reports.


Most of my coding involves very close interaction with forms and
reports, so I don't see how you can separate coding from the
process of UI design. Indeed, 90% of the work I do in Access is
UI design, and that involves forms/reports embedded in code, and
code embedded in the forms/reports.

It doesn't seem like something separate to me at all.


The relation between the Access UI and the schema is very
different from the relation between code and the UI or between
code and the schema. I presume you would agree. . . .


Not entirely.
. . . While we are
both agreeing that code can be made somewhat general in terms of
the forms and tables it works with (just aguing about when),
changes to the schema can easily break bound forms, and there's no
compiler to catch the problem, so it only turns up either in your
memory or in testing.
But my code is not separate from those forms, so changes to the
forms can break my code, unless I design my code to be as
independent as possible of the UI objects. That was the whole point
of getting rid of the control references in the AddPerson routine,
to make it possible to alter the form dlgAddPerson without breaking
that piece of code.
Implementing a 1-to-many relationship, there must be some
representation of this on the form, usually a master/subform
construct or something. This is very different from refactoring
(or implementing up-front) something along the lines of a
procedure that tries to invoke a GetEntityName method for an
arbitrary Form object, and adding the appropriate method code to
each form. In Access 2000 and above, you can even have each Form
module Implement an interface, so the compiler can validate the
code.
But you're ignoring the fact, I think, that I never recommended
building a UI for 1:N on the front end. I said that could be left
until the actual need for the N came up. The schema design enables
easier changes later, just as, in my opinion, the choice of code
architecture makes it possible to make changes to UI objects
without causing huge problems in existing code.

For instance, I wanted to change the names of the controls on
dlgAddPerson because the programmer used different naming
conventions than mine. With my AddPerson routine, I'd only have to
make those changes *within the form itself* (the code passing
parameters to AddPerson obviously would have to be changed). And
that's my point -- indeed, it relates back to your flirtation with
implementing the code to encapsulate your controls in explicit
functions so that you could get compile errors when using the !
operator. Your proposal there would have worked only within the
form itself, it would not have helped with control references from
outside the form itself. I'm basically proposing as a programming
principle that you *avoid* references to controls on a form from
any module except the form's own module. It's not that you'd
*never* do it, just that it's better to keep references to controls
on a form local to that form itself. If you need to deal with them
from outside the form, create an interface for it, either public
custom properties of the form, or create public methods to
manipulate the controls on the form as needed.
I consider this to be one of the biggest down sides of Access
because I would like to apply the same process I apply to code
to everything else in the app - but I don't because it doesn't
work.


I don't see that the code is that separate. I don't write
algorithms that are self-contained, I write code that
encapsulates processes that require interaction with human
beings, which of necessity is UI design.


But you said yourself that it's better for the code to be flexible
in terms of what forms it can work with. . . .


Yes.
. . . Access forms are
generally not very agnostic in terms of what schema they will work
with, though one can design the schema to be general enough to
increase the scope a single form will be able to cover. Again,
here's where schemas and form layouts are much harder to change
later than code is.
It depends on the code. If the code has been built to be dependent
on a single form and then you need it to be flexible to work with
multiple forms that are not exactly the same, then your code needs
to have exceptions built into that reflect knowledge of the
structure of those different forms. I say that's *bad design* and
think that it's better to build your forms and subroutines to use
interfaces that don't need to know anything about each other. In
that respect, it is definitely an encapsulation issue, but the main
point is keeping the need to know about objects outside the current
code context to a minimum.
...
I think designing your code has the same benefits from
experience. Certain kinds of activities you do on a regular basis
and know how to accomplish them, so you don't really have to
think about it. It's mostly when things inter-relate that you
have to worry about architecture, and when you have multiple
points of entry into subroutines.
And we agree on this point. I think we are only disagreeing on
-when- to make the code more general.


I'm not certain. I still don't think you're getting exactly what
I'm talking about. You're thinking I'm talking about internal
coding, where what I'm really speaking about is at an architectural
level.
Say you have a subroutine with a flag parameter that you are
using to skip whole huge swaths of the subroutine. That's a case
where there's a major architectural problem -- the optional code
ought to be in its own subroutine.


And I would definitely do this up front because it makes the
current code more clear. Anything that makes the code more clear
is fair game for that reason alone, and if it helps reusability as
a side benefit, that's cool too.


And that's *precisely* the kind of situation I'm talking about --
an architectural decision based on the choice of structures.
And that's precisely what I'm talking about in terms of
architecture.


That's why I'm saying out mechanical procedures probably don't
differ much, but I think changing the thought priorities has been
very helpful to me. Why clean this code? Because it's messy. If
it's clean, but doesn't handle every case I think it should
eventually be able to do, I leave it alone even if I think it's
easy. . . .


But you'd design it right the first time you encountered an
opportunity. Don't you do skeleton code with comments in places
where you know you're going to build something later but are not
implementing it yet? I do that all the time!
. . . Why?

1. There's a finite chance that I'm wrong about it being easy,
and once I start, I won't want to let it go.
2. There's a finite chance that something will come along before
the other case is needed that the extra code I wrote simply makes
harder to figure out how to factor in (cart before the horse -
sofa in the room before I know where it's going).
I'm talking about building structure. If you build a building that
you are contemplating adding 10 stories to, you'd better build the
foundation to allow for it, even if the 10 stories are never added.
This kind of thing often happens when you encounter a special
case. But the question is: handle the special case inline or hand
off the special case to a subroutine? I'd immediately choose the
latter, as long as the subroutine didn't need a gazillion local
variable values and would therefore require 2 dozen parameters to
be passed to it.


As above, I agree if the code is more clear with this change.


And that's the kind of architectural choice I'm talking about here.
Of course, once the code is written and works, then it's a
candidate for refactoring, but it would be well down my priority
list.


That used to be how I felt, but this is what is known as a
technical debt. If you have code that was not made as clear as it
could be when you were clear on how it worked, yuo have just cost
yourself extra time the next time you have to work with it. . . .


Or, you can follow the Larry Linson rule: Don't dink with working
code.
. . . This
cost will be incurred each time you revisit the code. It costs
with interest. Also, the refactored code may expose options for
later resues that were not otherwise evident.
Well, I tend to *not* change working code unless it has to be
changed because it is required by new contexts that it do more than
what it was designed to do. In other words, I don't refactor just
to clean it up -- I only refactor in preparation for
enhancing/revising.
[]
I have one app that I really regret the schema I created. It
seemed an obvious thing to do, using a supertype table and
multiple subtype tables, but it's turned out to be a nightmare in
the end. Possibly I didn't think through the design so that I
properly designed my class modules for it, but somewhere along
the line, things are just not working, and I have one helluva
time keeping the code working reliably.

And I've refactored that code twice already!


That's definitely one you only learn by doing it wrong, eh? I
tried something similar with similarly awful results. I'm still
not even sure -why- it comes out so awful.


I still think my initial design was on the right track. I just
don't know for certain where things went wrong.
...
But, Steve, you'd never create your Person class, because you'd
never be able to justify all that work for no purpose, no? ;)


It would be jsutifies as soon as I had the second or third use
case. I would refactor the code, and move most of it to the class
module.


So, I take it, then, that you already have a working Person class?
;)

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #49

P: n/a
On Thu, 18 Sep 2003 23:00:59 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:7c********************************@4ax.com.. .
On Thu, 18 Sep 2003 01:36:32 GMT, "rkc"
<rk*@yabba.dabba.do.rochester.rr.com> wrote:
....I believe delegation and containment are two terms that mean the same thing.
You delegate a task to an object contained in another object.
Well, I think you got it right and wrong at the same time. Delegation and
containment are not the same thing since you can contain without
delegating. By delegating, I mean that you wrap functions from the
contained class in simple forwarding functions with identical signatures.
You "expose" the methods of the contained object.
I don't understand why you say 'It only works well when you can keep the
number of delegated members relatively small'. If you have a vehicle object
that you want to use as the basis of a bulldozer object it doesn't work any
less well whether the vehicle object has 12 properties and methods that
apply to a bulldozer or 2 properties and methods that apply to a bulldozer.
Are you talking about a degradation of performance?


I'm talking about the maintainability of the code. If you're using
containment with delegation as a substiture for inheritance, you have to
write and maintain all those wrappers. Code that has maintenance
difficulties often doesn't get maintained. Thus, this model works best if
there are only a few methods delegated.
Nov 12 '05 #50

55 Replies

This discussion thread is closed

Replies have been disabled for this discussion.