|
Posted by Al Dunbar on 12/07/05 08:41
"Highlander" <tron9901@msn.com> wrote in message
news:1133482432.710124.52790@g49g2000cwa.googlegroups.com...
> Al Dunbar wrote:
>> "Highlander" <tron9901@msn.com> wrote in message
>> news:1133322022.454485.96000@f14g2000cwb.googlegroups.com...
>> > Al Dunbar wrote:
>> >> "Highlander" <tron9901@msn.com> wrote in message
>> >> news:1133209896.037785.269910@o13g2000cwo.googlegroups.com...
>>
>> <snip>
>>
>> >> > Sub Window_Onload
>> >> > self.Focus()
>> >> > self.ResizeTo 600,500
>> >> > self.MoveTo 200,50
>> >> >
>> >> > ' Clear all variables in order for the
>> >> > ' "Enable Change Database button" IF statement to work
>> >>
>> >> Would not be as much of an issue if you avoided using global
>> >> variables.
>> >
>> > Since the "Enable Change Database button" IF statement has to be in all
>> > 3 subroutines (ServerButton, ReleaseSelectList and DBSelectList), I had
>> > to make the 3 variables (strServer, strRelease and strDatabase) global.
>>
>> As you wrote it, perhaps, however I try to avoid global variables at
>> almost
>> all costs.
>>
>
> That's my point - is there another way to write it?
For any given possible program there are many ways to write it. What I am
suggesting is not to mechanically do something to the code so that it no
longer relies on global variables. The only way to really achieve a change
in this direction is to re-think your overall coding strategy to avoid this
potentially dangerous dependency. The reason for doing this is primarily to
improve maintainability, but having me show you how I would have written
this particular script would not likely be too useful for you.
> You mention below
> that there may be other ways, i.e. put that code in a small subroutine
> and call it from wherever you need to.
>
>> > Done.
>> > Extracting the common code from the true and false blocks worked great.
>> > I used this same logic in other areas of the script and overall I
>> > trimmed between 25 and 30 lines. Thanks Al!
>>
>> The issue is not trimming lines; the issue is the simplicity and
>> maintainability of the code.
>>
>
> That makes sense. I would imagine though that trimming the code and
> removing redundancy where you can is part of making it simpler and
> easier to maintain.
>
> Ideally a script would be written "right" in the first place, the right
> logic, right commands, right format, etc.
Ideally, yes, however, one way to avoid problems is to never make the
assumption that your code is correct. In fact, almost all code could
probably have been written better. It just will not be written better until
the writer of the code learns to believe that "almost all code could
probably have been written better".
> Simplicity and
> maintainability would be there from the outset. In my case I don't have
> the experience and never learned VBScript from the ground up, the
> basics, the guidelines, etc. I create scripts in a crude way, by
> bolting together code snippets from many different sources, and then
> attempting to pare it down so that it has some semblance of efficiency,
> simplicity and maintainability.
That is a completely accurate description of how many of us have learned to
script (or to program). And it is done this way, IMHO, because there is not
enough emphasis placed on how to structure code to make it simpler. Some of
the standard exhortations (declare all variables at the top...) Are fine to
just get a person going and functional, but what we really need is an
approach to making the code truly modular and reusable. I do it my way, but
that is not the only way.
> That's why I value your opinion (as
> well as other helpful responders on Usenet) highly. You help me get
> there.
Thanks - on behalf of all those other helpful people out there :-).
>> > Any suggestions on my remaining questions?
>>
>> I didn't answer them all before because you posted a script of nearly 400
>> lines. As it is, and without doing an exhaustive (and exhausting)
>> analysis
>> of the whole thing (which would require a lot of deductive reasoning to
>> figure out), all I can do is make a few suggestions based on what I see
>> in
>> your code (see a few more way below...). Unfortunately, it might be that
>> a
>> better next version would actually do things differently.
>>
>> > - The conditional IF statement used to enable the "Change Database"
>> > button...I've had to put it in multiple subroutines. Is there a better
>> > way?
>>
>> You could put that code in a small subroutine and call it from wherever
>> you
>> need to. This would localize your references to these global variables.
>>
>
> Can you give me an example of what this small subroutine would look
> like, and how I would call it?
OK, so, you have instances of code like this:
' Enable Change Database button when all criteria is selected
If strServer <> "" and strRelease <> "" and strDatabase <> "" Then
ChangeDatabase_button.Disabled = False
If you leave the variables as globals for now, you could replace the above
statement with:
AdjustDBbutton
and create this sub:
sub AdjustDBbutton()
If strServer <> "" and strRelease <> "" and strDatabase <> "" Then
ChangeDatabase_button.Disabled = False
end if
Not much saved there, however, it is less likely that you would introduce an
undetected error by mistyping the long if statement.
The trouble with global variables is that any of your code could
unintentionally alter those variables, and it would be difficult to figure
out where this is happening. This is where some of the concepts of object
oriented programming come in: if the only access to some persistent data
storage is through a set of routines, then that set of routines can be
designed to help prevent errors.
Short of creating classes and instantiating objects from them, this can be
simulated with a pair of functions for each such "value". For example, the
strServer concept could be managed with code such as:
private STRSERVER_PERSISTENT
function strServer()
strServer = STRSERVER_PERSISTENT
end function
sub setstrServer(value)
STRSERVER_PERSISTENT = value
end sub
Then you would change all instances of "strServer = some_value" to
"setstrServer some_value", and all other instances of "strServer" would
remain unchanged in your code, i.e.:
strServer = cboServerSelection.Value
would become
setstrServer cboServerSelection.Value
Then any of the references to the old strServer variable (which should no
longer be DIM'd anywhere) will receive the stored value as the return value
of a function instead of directly from a global variable.
Seems like a lot of work, no? Well, I basically did that in one project I
was working on, and once I had made the changes I found things suddenly got
simpler. As an aside, note that the "STRSERVER_PERSISTENT" variable declared
by the "private STRSERVER_PERSISTENT" statement *is* a global variable. But
it is one that, according to my convention, aught not to be referenced
outside of the function and sub pair that "owns" it.
I'm not suggesting that you should mechanically make the equivalent changes
wherever you have a global variable. As I started down that road, I found
that there were other ways to reduce my dependence on the "global" aspect of
global variables. If your coding approach rules against using global
variables in the first place, there will likely be fewer instances where
they need be simulated as above.
>> > - I'm using the sysinternals.com utility PSEXEC to remotely change the
>> > Registry. Is there a better way?
>>
>> There are other ways. What is it that you might think needs improvement
>> in
>> this aspect of your script?
>>
>> > - I'm using the sysinternals.com utility PSEXEC to remotely restart
>> > IIS. Is there a better way?
>>
>> There may be other ways. What is it that you might think needs
>> improvement
>> in this aspect of your script?
>>
>
> I just wondered if there is functionality within VBScript syntax that
> will perform the same tasks. Although shelling out and using PSEXEC
> works fine in this script, I just considered that using inherent
> VBScript capability (if it exists) is "cleaner" than shelling out and
> using 3rd party utilities.
I understand and agree. Unfortunately, some of the things that are simple to
accomlish by calling external utilities require a pile of coding to
accomplish in more VBScript-exclusive ways. One good example is changing
NTFS permissions - a whole lot easier to call cacls.exe than to write the
corresponding vsbcript code from the ground up.
As to how to remotely start IIS, I have never had to do this so have not
researched it. Changing the registry remotely could likely be done with WMI,
but that can be a whole 'nuther can of worms, and one I have lost the opener
for.
One final (for now) hint: you seem to have the ability to look at a problem
and work out a solution for it in code - an admirable skill, in fact. Use
that same skill on the following problem: "here is how I code, how can I do
better?". And don't forget that, in addition to deductive reasoning, you can
use experimentation ("let's try this a couple of ways and see which works
best, is simplest, is easiest to understand, is harder to get wrong, etc."),
and informal statistical analysis. For example, you could informally track
how much actual trouble you have working on a couple of different projects
and correlate that with the extent to which variables are global, the
proportion of the code that is in script-level scope versus functions and
subs, and etc, this might help you figure out why some coding models are
better than others.
/Al
Navigation:
[Reply to this message]
|