Friday, February 16, 2007

Commonality and Variability

Following the same thread towards commonality-variablity analysis, a practical and common-sense approach to designing abtract and concrete classes by distinguishing common behaviour of a class-of-types from their distinct variable behaviour from each other within that class-of-types.

I was just refreshing my memory about commonality-variablity analysis (see James O. Coplien, et al) and I noticed the first reference D.L. Parnas et al., "The Modular Structure Of Complex Systems," IEEE Trans. Software Eng., Mar. 1985, pp.408-417.

Prof. David L. Parnas was the keynote speaker the Australian Software Engineering Conference I recently attended in Brisbane. An inspirational speaker, he is "one of the grandmasters of software engineering." (see). "Software Fundamentals: Collected Papers by David L. Parnas is a practical guide to key software engineering concepts that belongs in the library of every software professional." (ibid; see also).

I was privileged to have the opportunity to sit down and chat with Prof. Parnas on several occasions over the course of the conference and found him to be a gentleman and still passionate about software engineering, licencing and education or professionals in our field. One of the recurrent topics is the content and quality of University education.

Recently, I had the opportunity to give a seminar in CS at UWA about Java, C++, type-safety and emergent design, in part motivated by discussions with David and also stimulated by thoughts from Douglas Hofstadter's fabulous Godel, Escher, Bach: An Eternal Golden Braid.

You haven't read GEB? I heartily recommend it as a glorious and stimulating mental roller coaster for all readers.

Which programming language to teach?

Having just stumbled across these comments in a personal email I sent to a colleague about what programming languages to teach, it seems a good idea to reporoduce it here. Not intended to start a flame war but rather to offer a commercial perspective on the relevance of the various languages in undergraduate teaching at university. My reply to his question is shaped by my thoughts having just returned from ASWEC 2005, held in Brisbane, Queensland.

I have strong feelings about the structure of undergraduate and postgraduate courses at university. I had discussions with several people at the conference, including world expert Prof. Parnas, one of the keynote speakers, and several others about problems with course content, mainly the tension between science, IT, CS, fundamentals, engineering accreditation, resources and so on. An enduring feature of these discussions is what languages to teach.

I think UWA has traditionally had a good balance however the recent lack of strong C/C++ teaching has been a disadvantage while Haskell, and functional languages, are closer to much commercial reality when code generation and style-sheet processing (like grammars, parsing and rules application eg. make, ant, xslt, yacc/lex) are involved. Lisp, prolog and their ilk are yet another kettle-of-umm-fish.

My personal feeling is that Smalltalk and Eiffel have limited applicability in commercial applications. My main reasons are that they lack flexibility and sufficient object-oriented constructs, are overly rigid and, as a result, never achieved commercial acceptance. I will state, however, that Smalltalk concepts are endemic through the community and have found a place in other languages and common practice, C# delegates and C++ Boost function prototypes being modern implementations of Smalltalk message passing based on method signatures rather than, for C++ and others previously, where an explicit, common base class has been required for polymorphism and dynamic dispatch to take place.

Teaching of these languages, or similar, must be mandatory because otherwise there is no sense of history and development, for one thing, and they also provide a platform for describing improvements (not always the case though) through language evolution. As Isaac Newton said, "If I have been able to see further, it was only because I stood on the shoulders of giants."

My reasons for and against Smalltalk and Eiffel, neither of which I have used in earnest, follow. Sigh. Single inheritance means that natural object hierarchies cannot be built. Same objection against Java and C# managed components. Leads to code duplication and in some cases jumping-through-hoops to achieve satisfactory design. For example, p->impl-ing a class to implement a sort-of decorator which delegates to the another class. Certainly we prefer composition to inheritance however the mixin is incredibly useful and, importantly, leads to a very simple design, most important for understanding, and implementation, less important except directly impacts on maintenance costs over lifetime of component.

Similarly for const-correctness in C++, lacking in the others, where this additional contract improves code robustness. We use the const idiom in Java, the read-write interface extending the read-only interface (Aro <- Arw) in order to get similar, but without type safety. Eiffel programming by contract is a design principle and has some arguments to its merit, expressing invariants in code, however the mechanism is rigid and hence brittle. I argue the same for Ada.

Specifically, it is unnecessary, even wrong, for whole families of constraints to be captured in source code and caught at compile time. Static type safety is, I believe, fundamental to building robust software. However, pre and post conditions are run-time constraints so they are of less benefit than contraints imposed by the "interface contract" of a base class or interface. Early failure is as desirable as late binding and lazy initialisation.

An open question on requirements capture is occupying my thinking, and I should be generating a paper on equivalence between typographical, textual requirements, formal specification (eg. Z or object Z), use cases and invariants asserted in test cases. Trying to capture all of the same information is more than one layer of abstraction is of questionable value because it appears that instead of a higher-level language being used for analysis, requiring a tranformative step and further elaboration (eg. detailed design) it is assumed that direct translation can be used. Which is pointless.

Consider that if the specification language can be translated to an implementation then it is just another isomorphic implementation language. Oddly enough, that is how in the limit I tend to describe all of the modern programming languages - as syntactic variations of Algol. Maybe that's a bit extreme. Include Lisp: Treat modules and classes as metaconstructs. Maybe not. I treat comments as part of the interface contract. Test-driven development exercises these constraints as well.

So there you have it. Teach all of the programming languages. Keep them in context. Stand on the shoulders of giants.