comp.lang.ada
 help / color / mirror / Atom feed
From: Stephen Leake <stephen_leake@stephe-leake.org>
Subject: Re: [SPARK] Code safety and information hiding
Date: Sun, 20 Aug 2006 15:06:04 -0400
Date: 2006-08-20T15:06:04-04:00	[thread overview]
Message-ID: <uu047jkgz.fsf@stephe-leake.org> (raw)
In-Reply-To: %%QFg.913090$084.629274@attbi_s22

"Jeffrey R. Carter" <spam.not.jrcarter@acm.not.spam.org> writes:

> Stephen Leake wrote:
>> I think I'll choose to take offense at this statement (it's 5:26 AM,
>> and I can't sleep because I've got a bit of the flu, so I claim the
>> right :).
>
> I have a bad cold, and did when I wrote the statement to which you're
> responding, so I claim the right to argue back. Let's spray our addled
> perceptions into c.l.a, where someone will reference them as
> definitive in the future.

Ok, sounds like fun :)

>> I have an application called Goddard Dynamic Simulator (GDS); it is
>> used to test flight software and hardware for NASA Goddard (yes, I am
>>  a rocket scientist). It has 90,000 lines of code, mostly Ada, some C
>>  and VHDL.
>
> I've never been sure what a "rocket scientist" is. Is it someone who
> deals with the theory of anaerobic propulsion systems? Or is it a more
> general science dealing with launch systems overall?

In this case, it's anyone vaguely associated with launching rockets,
or working for NASA. It's intended as an assertion of authority,
hoping to instill fear and obediance in the audience.

> In any case, being a scientist is probably not a qualification for
> designing actual systems. Scientists deal with theory; engineers with
> creating systems. Physicists are not necessarily competent to design
> bridges; civil engineers are.

Good point. But "rocket scientists" are actually typically engineers.
The original term was for the people who made the first large rockets
actually fly; they were certainly engineers.

>> However, there are some global variables. I thought long and hard
>> about each one, and decided they are the best solution to the
>> problem.
>
> Some is probably better than lots. 

Agreed.

> With "some" they might be well documented. 

They are.

> As I've said, I've seen large, safety-critical systems designed
> around thousands of undocumented global variables. 

Ok, that's definitely bad.

I haven't seen a system with that particular flaw, but I have seen
plenty of bad systems.

> I think it would be faster and easier to redesign and reimplement
> these systems than to understand them well enough to safely make
> changes to a small part of them.

Yes.

>> This design has evolved thru several iterations of similar systems.
>> They all have a global symbol table.
>
> So, as a modifier of the system, without reading and understanding all
> parts of the system that may access this variable, it's OK for me to
> write to this variable whenever it's convenient?

Of course not. Now you are setting up a strawman.

In my system, as you alluded to above, the use of each global variable
is well documented; programmers are expected to follow the rules in
the documentation. 

Of course, every time I add a new programmer to the team, they
discover new ways to (mis-)use the globals that were not covered by
the documentation :).

>> type Distribute_Mode_Type is (Master_Mode, Remote_Mode, Single_Mode);
>> Distribute_Mode : Distribute_Mode_Type := Single_Mode;
>
> Again, it must be reasonable and meaningful for me to change the SW to
> write this variable whenever it suits me.
>
> If that's not the case, then I claim this should not be a variable.
> Instead of being able to write
>
> X.Distribute_Mode := X.Master_Mode;
>
> I should have to call something like
>
> function Request_Distribute_Mode_Change
>     (New_Mode : Distribute_Mode_Type)
> return Boolean;
> -- Request mode change to New_Mode.
> -- Returns True if the mode change is legal; False otherwise.
>
> All the details of when a mode change may occur should be encapsulated
> with the current mode value.

Ah. You want the code to enforce the design rules. That's not possible
in general. Ada allows enforcing some design rules, but not ones at
this level.

In fact, for this particular variable, the rule is "only the
environment task may write to this variable, and only before any other
tasks are started".

People modifying the code must understand the design.

I have been tempted to write some ASIS programs to enforce more of the
design rules. One that people keep breaking is "modules must not write
to their own Input symbols". But this would be a complex program
(worse than Auto_Text_IO, for example), so I haven't done it yet.

Hmm. Now that I think about it, it would be easy to implement a
run-time check for that rule. But it would be a waste of time in the
production system. Might still be worth it; I have other run-time
checks for similar rules (in particular, "symbols must be written
before being read") that are hard to check otherwise.

> On the 3rd hand, systems generally are either distributed or not, and
> that doesn't change during execution. In that case, this is
> essentially a constant. If the actual mode is determined at run time
> during start up, then probably the value should be encapsulated with
> the logic that determines it, and the resulting value be made
> available to the rest of the system through a function.

That would be essentially a globally visible getter/setter; the getter
must be globally visible, but the environment task which calls the
setter should not be. I don't see any way to enforce the rule of which
task is allowed to set the variable at run time.

In practice, the rule of how this variable is set has never been broken.

> In this latter case, there may also be a race condition. What if one
> part of the system reads this and gets the default value before its
> actual value is determined? It's probably better to control that
> locally than otherwise.

In general, that's a reasonable goal. In this particular case, it's
not possible.

>>    Ignore_Hardware_Errors : Boolean := False;
>>    --  Set True for unit tests when hardware is not present or should
>>    --  be ignored.
>
> Shouldn't that be "Boolean_Type"?

It would be if I was writing the Ada language. We're stuck with
"Boolean". 

> This is documented, and shows that it isn't a variable. Clearly this
> should have the same value for an entire execution; I've never seen SW
> that switches between unit test and other modes during execution. I
> suspect your SW would be clearer if this were a constant.

During any particular run of the full production system, this is a
constant; usually False but occasionally True (if some important
hardware is absent). Thus it is set by the environment task at
startup, just like Distribute_Mode.

During runs of many unit tests together (under an AUnit test harness),
this value changes between False and True. Some unit tests use
hardware emulation code, and can check for hardware errors. Other unit
tests have no emulation code, and must ignore them.

>> I claim to be competent to design SW; I have 20 years of experience,
>> and at least 10 monetary awards for outstanding performance, together
>>  with high praise from my (internal) customers, to prove that. My
>> system has a few global variables because they are the right solution
>>  to the problem.
>
> Perhaps. Who modifies the system? 

That is the important question. For now, it is a team led by me.

> Add 1 undocumented global variable to a system, and you generally
> increase the coupling and decrease the cohesion. 

That is not just true of variables; add 1 undocumented
function/procedure/package/task to the system, and you have a problem.

The key notion here is "documentation"; any system must be documented,
so that maintainers understand it before modifying it.

> You understand the system, but after you're hit by a truck, how easy
> is it for someone who doesn't have any experience with the system to
> figure out how it works?

That is the important criterium for how good the documentation is. 

When one of my team members or customers asks a question about how to
use the system, I try to look in the documentation to answer it first.
If the answer isn't there, I fix the documentation as the answer to
the question.

Of course, when there's a crunch on, questions get answered more
directly. So the documentation isn't perfect. But it is intended to be
adequate. 

>> You have not said why getter/setter would be better for these
>> variables. I agree with Robert; they are just more verbose.
>
> I don't think they're better. I said that if global variables were not
> available, those who would try to base their designs around them might
> not think of using such operations to mimic them.

Hmm. I guess I don't know what you mean by this. Above, you suggested
replacing Distribute mode by a getter/setter, where the setter
enforced the design rules. I assumed you meant that getter/setter
design was better than the global variable it replaces. Now you are
saying something else, but I don't know what.

>> Hmm. You could try to impose control over what parts of the system
>> are "allowed" to write the variables, as opposed to reading them. But
>> that would require an elaborate system of IDs for various parts of
>> the system (which does not otherwise exist); definitely not worth it.
>
> You might simply document who may write and who may read such
> variables. 

That is what I'm doing.

> That would be a big improvement in the global-centric systems I've
> seen. Of course, that goes against the basic Ada philosophy that
> packages should not be concerned with who their clients are. 

While that philosophy is useful for packages that encapsulate a
logical function, it is clearly not true for packages that declare
global variables; they exist precisely for the use of the system as a
whole, not of the package that happens to declare them.

As with most other good ideas in design philosophy, there are times
where this one doesn't work.

> That's something that's not always achievable in large, real SW
> systems. 

Exactly.

> In general, values should be encapsulated with the logic that
> generates or modifies them, 

Yes. And "the logic" can be as small as a 10 line function, or as
large as a 90k multi-cpu program; each has need of some state that is
visible to the entire subsystem.

> Now, I've worked on systems with physical redundancy, so that one
> processor is the currently active one, and the others shadow it and
> are prepared to take over if it fails. I've worked on such systems
> where the determination of which is the active processor is made by
> another part of the system, so it is necessary to distribute that
> value to the processors. In that case, the SW pretends that it
> determines the value; for example, there's a module that encapsulates
> the value and provides access to it to other parts of the SW. There
> isn't a procedure Set for the value; rather, the module has an
> operation that receives and processes the message that changes the
> value.

How did you set the variable in unit tests?

>> I'll make a counter claim; people who claim global variables are
>> _always_ bad should not be designing large complex systems; the
>> systems will be more complex than necessary, which is definitely a
>> Bad Thing.
>
> I have over 30 yrs of professional SW development experience, and I
> still find myself doing things I know I shouldn't. 

That's true for me as well.

> Hopefully I catch them most of the time in the important cases. But
> I've seen people with decades of experience who are not competent to
> design any meaningful SW. 

Also true.

> They're among that large proportion of developers who will never be
> more than coders. Customers are happy with anything that works and
> they can afford; I've seen customer satisfaction with very poorly
> designed SW.

That I have not seen. Well, I guess I have to count Microsoft software
in that; some people seem happy with it.

But all poorly designed systems that I know of, in my area of
expertise, have unhappy customers.

> There may be cases where global variables are the correct design
> approach, but I have yet to see one.

now you have :).

>> While it is true that all SW people are not equal, I don't see what
>> that has to do with the issue of global variables, nor do I see what
>> problem recognizing that might be a solution to.
>
> Once you recognize that, you don't allow the coders to design SW. That
> gets rid of most poor design, including designs with large numbers of
> undocumented global variables.

"large numbers" and "undocumented" are the key here, and as I pointed
out above, that description applies to other aspects of the software
as well; large numbers of small functions, or large numbers of
threads, are just as bad (possibly worse) as large numbers of global
variables.

> I'm not saying the GDS SW is poorly designed (I've seen enough of
> your work to suspect it probably isn't),

Ok, good. However, I think you will agree that your initial statement
implied that it was, since it does have some global variables. Which
is why I responded.

> but I suspect that the design could be improved and that the
> improvement would eliminate the global variables. 

The design could certainly be improved. But eliminating these global
variables isn't even on my list.

> Whether the improvement in design quality would be worth the effort
> to achieve it now, I can't say. At the time of initial design, it
> almost certainly was.

Well, that is a judgement call. At the time of the initial design, I
decided that eliminating the global variables was more costly than the
risk of them being misused. 

It does depend on the quality of the maintenance team; whether they
truly understand the system before modifying it. But someone who
doesn't understand a system will still be tempted to "just add a
global variable to fix this". Which is why adding complexity just for
the sake of reducing global variables is not worth it; it makes the
system that much harder to understand.

-- 
-- Stephe



  reply	other threads:[~2006-08-20 19:06 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-16  7:56 [SPARK] Code safety and information hiding Maciej Sobczak
2006-08-16  8:53 ` roderick.chapman
2006-08-16 11:18   ` Stuart
2006-08-16 13:23     ` Maciej Sobczak
2006-08-16 19:49 ` [SPARK] " Jeffrey R. Carter
2006-08-17  7:01   ` Maciej Sobczak
2006-08-17 18:08     ` Jeffrey R. Carter
2006-08-17 20:00       ` Björn Persson
2006-08-18  1:22         ` Jeffrey R. Carter
2006-08-18 19:39           ` Björn Persson
2006-08-19  5:35             ` Jeffrey R. Carter
2006-08-19 12:47               ` Björn Persson
2006-08-20  3:58                 ` Jeffrey R. Carter
2006-08-20 11:35                   ` Björn Persson
2006-08-18 23:02   ` Robert A Duff
2006-08-19  5:40     ` Jeffrey R. Carter
2006-08-19  9:49       ` Stephen Leake
2006-08-20  3:52         ` Jeffrey R. Carter
2006-08-20 19:06           ` Stephen Leake [this message]
2006-08-21  1:07             ` Jeffrey R. Carter
2006-08-21  7:25               ` Maciej Sobczak
2006-08-21 19:31                 ` Jeffrey R. Carter
2006-08-21 19:58                   ` Dmitry A. Kazakov
2006-08-21 21:06                     ` Björn Persson
2006-08-22  7:16                       ` Maciej Sobczak
2006-08-22  9:45                         ` Björn Persson
2006-08-22 12:42                           ` Maciej Sobczak
2006-08-22  7:27                       ` Dmitry A. Kazakov
2006-08-21 11:30             ` Colin Paul Gloster
2006-08-22 10:51               ` Stephen Leake
2006-08-23  9:44     ` Peter Amey
2006-08-23 22:37       ` Jeffrey R. Carter
2006-08-24 10:55         ` Peter Amey
2006-08-24 23:33           ` Jeffrey R. Carter
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox