----- Original Message ----- From: "Julian Leviston" <[email protected]>
To: "Fundamentals of New Computing" <[email protected]>
Sent: Wednesday, October 13, 2010 9:13 PM
Subject: Re: [fonc] Spec-Driven & Self-Testing Code



On 11/10/2010, at 12:24 PM, BGB wrote:

<--
Does anyone know about a language (possibly something in smalltalk) that involves spec-driven development?

A language that stipulates a spec (in code - ie a test) must be written before any code can be written, and that can also do self-checks (sort of like a checksum) before the code is executed?

Julian.
-->

possibly relevant questions:
what would be the merit of imposing such a restriction?
how would one enforce such a restriction?
how could this be done without compromising the ability to use the language to get much useful done?
...

IMO, any such restrictions are better left under the control of "the development process" rather than trying to enforce them at the language level.


<--
The merit of imposing that users write specs first assumes that programmers have a plan before they start writing code, and then encourages them to become aware of their plan and requirements, explicitly laying them out in a series of test of behaviour. (See http://behaviour-driven.org/ possibly for a good explanation of where I'm coming from here).
-->

quick skim of some of it...

ok, there seems to be a conflict here...

writing specs/plans, and testing quick/early, are very different approaches to software design.


in a typical spec or plan-based process, a person will try to work out everything in advance, and delay coding until after the spec is relatively complete. this is what is usually termed "waterfall method" or "BDUF".

waterfall: first spec; then code; then test and debug; then deploy.


in a test-driven setup, usually the tests and code are written early and written alongside each other, and planning is usually very minimal (usually just writing out maybe basic ideas for what the thing should do).

in this later form, usually specs are written *after* the code, usually either to document the code, or to help identify which directions they want to go, ...

this would seem to be more the style advocated by the posted link.


it seems like there is jumping between advocating several different methodologies.

admittedly, I tend to combine both strategies, usually writing specs for individual components or features, but using an incremental process and regular testing for large scale features.


<--
I'm not advocating enforcement, rather encouragement. As most of us know, you cannot happily enforce things on people, let alone programmers - for example Java's nightmarish type system hinders more than helps (in my humble personal opinion, only). One *can* encourage certain things through the FORM of the language/IDE/workspace/etc., though (for example, smalltalk's class browser encourages a programmer to think in terms of classes)... unfortunately composition might be a better practice most of the time and it *may* be that having a class browser as a default tool encouraged the "over-use" of inheritance that we have seen as quite a dominant practice/idea in the OOP world.
-->

enforcement also usually only works when there is something well defined to enforce, or something can be enforced in terms of taking away some specific feature.


<--
What I *am* advocating, though, is a checksum that is written by testing suites at various levels that would mean that code wouldn't run unless it had at least the most basic testing suite run against it. I'm advocating that behaviour-tests should be a mandatory part of development (any development process - be it writing a song, programming a program or building a house). The best of us as developers in any realm do these kinds of requirement-conformance "tests" when building whatever it is we're building ANYWAY, so I see it as simply a formalisation of a hitherto unexpressed best-practice.
-->

IMO, "checksum" is also a bad choice of a terms to use in reference to unit tests or similar. typically, what a checksum does and what a unit test do are very different, and it would create unneeded confusion to use one term to describe the other.

the problem is (with the proposed idea), until both code and tests can be written, one is almost inevitably going to write a test which always passes, so that they can run the code, effectively so that they can in turn test and debug the code.

traditionally, code will be run regardless of whether it is known to work, and the main point of unit testing then is to start throwing up red-flags that something may need to be looked at or fixed, or to track new functionality which "should" work, but doesn't as of yet (if wanting to add a new feature may make the test fail, which may break the build, then people are going to delay adding the test until after the feature is generally known to work, partly defeating some of the purpose of unit testing).


<--
Code should simply be able to test itself, to perform minimal self-diagnostics in the same way that advanced photocopiers or computers can do this. If we bake this in at a micro-granular level, then the reliability and stability of systems will skyrocket. Not only this, but code essentially self-documents then. If we are as programmers, encouraged to document before *and* after we write code, we will end up with a neat description of what we were trying to do and not just the output.
-->

usually I just write tests as little special-purpose frontends which test that a piece of code works as expected. I have tried using these for my C compiler as well, but sadly I am then left to realize that my compiler is partly broken (some tests fail for "reasons not yet identified", seriously, in some cases I comb through the ASM output and still can't find the cause of the error), and I have neither the time nor the energy to really beat all the bugs out of it (my main codegen was written with, sadly, very little testing, and is very internally complex, so sadly it is left on faith that a lot of this stuff actually works...).


sadly, some pieces of code, particular compilers, are somewhat difficult to test on a fine-grain basis, and so have to be tested on a more coarse scale: if fragments of code compile and behave as expected. this leaves a lot of need for manual intervention in testing and debugging, such as reviewing the output of various internal processes, trying to track down specific errors (in possibly a large mess of other data), making debugging a relatively labor-intensive process.

this is, sadly, an ongoing battle in my cases.



<--
As a community, I'm trying to get us to shift from being the kid in maths class who says "12" when the teacher says "What is 3 times 4"? The working out is at least as important as the answer... as we all know in later mathematics, more weight is attributed to the process than to the outcome... if there are 12 steps in a process to build an answer, and only the 12th is incorrect, then that is 11 out of 12 as a score, as averse to if there is only an incorrect answer and no working out, that is 0 out of 12 as a score... or 12 out of 12 if it is correct.

Do you see my point here?
-->

hmm... not all of use are good with maths...


<--
Of course, just as it's possible to write structured code inside Smalltalk, or any Object-Oriented language, it would be possible to "get around" this encouragement of behavioural-driven-testing built into a language. But that's beside the point. I'm not trying to get to a state where things are IMPOSSIBLE to break. I'm trying to get to a state where they're encouraged to work.

If I didn't want to write tests, I could simply write tests that evaluated in true. Hands dusted and done. Mind you, the stakeholders (maybe me) would probably get frustrated as the project gets larger and more regression errors creep in with each suite of changes imposed on the system.
-->


even OO is not a requirement:
even though OO is popular, not everything needs to be OO or in an OO language, and OO or not-OO is really a side issue to the matter of unit tests...



sadly, if the tests prevented the project from building or running if they failed, this would essentially leave the tests always (or almost always) evaluating to true as the only really reasonable outcome in most cases...

granted, testing could have separate "warning" and "error" conditions, where a warning condition is a test which fails, but the code can still be run (only something minor has broken, or correct behavior remains as a future goal), and an error condition is where "something has just gone horribly wrong here", with the assumption that the test itself can be used to help debug the problem.


often, it is still needed to run even known broken code in order to help better isolate the problem. now, preventing doing an official release with broken code is an altogether different issue...


or such...


_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc

Reply via email to