Classic paper: On the Criteria To Be Used in Decomposing Systems into Modules
Summary: my comments on a classic paper by David Parnas
I would advise students to pay more attention to the fundamental ideas rather than the latest technology. The technology will be out-of-date before they graduate. Fundamental ideas never get out of date. However, what worries me about what I just said is that some people would think of Turing machines and Goedel’s theorem as fundamentals. I think those things are fundamental but they are also nearly irrelevant. I think there are fundamental design principles, for example structured programming principles, the good ideas in “Object Oriented” programming, etc.
Uno dei pochi, pochissimi principi universalmente accettati nell’ingegneria del software è che l’unica maniera di scrivere un programma di grandi dimensioni è scomporlo in moduli. Quello che non è completamente chiaro è come scomporre il sistema in moduli; qual è un principio razionale per decidere quale funzionalità deve andare in quale modulo? Questo problema sembra banale, e non degno di attenzione accademica. Eppure è fondamentale per la realizzazione di un buon design.
When you watch programming from the outside, everyone seems to love the hard problems and its widely celebrated as the interesting accomplishments.
But there are so many simple problems that haven’t been solved. Or haven’t been solved well. I’d rather solve them.
David Heinemeier Hansson, Not so clever; or why I don’t like hard problems
Nel suo classico On the Criteria To Be Used in Decomposing Systems into Modules, Parnas sostiene che ogni modulo esiste per nascondere un segreto. Il termine “information hiding” è opera sua. Un’altra maniera di vedere questo concetto è di pensare a tutte le decisioni di progetto che bisogna prendere per realizzare un sistema: quale algoritmo, quale database, quale … e nascondere ciascuna di queste decisioni in un modulo. E come possiamo valutare la bontà di una scomposizione in moduli? Si ipotizza di cambiare una decisione, e si vede se ci tocca modificare un solo modulo (bene) oppure più di un modulo (male).
The … decomposition was made using “information hiding” as a criterion. The modules no longer correspond to steps in the processing. The line storage module, for example, is used in almost every action by the system. … Every module … is characterized by its knowledge of a design decision which it hides from all others. Its interface or definition was chosen to reveal as little as possible about its inner workings.
…
We have tried to demonstrate by these examples that it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart. We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others. Since, in most cases, design decisions transcend time of execution, modules will not correspond to steps in the processing.
E’ difficile non essere d’accordo con Parnas: ogni modulo racchiude una decisione. Realizzare questa idea però può non essere facile in pratica. Credo che ci vogliano esperienza, fantasia e impegno per riuscire a “contenere” le decisioni in un modulo, in maniera che sia possibile poi modificare queste decisioni senza alcuna ripercussione sul resto del sistema. Io vedo questo come un’istanza del problema di rimuovere la duplicazione.
Ad esempio, se nel mio programma Java devo leggere dei file, mi ritroverò a scrivere questa noiosa pappetta in più punti del mio programma:
BufferedReader in = new BufferedReader(new FileReader("infilename")); String str; while ((str = in.readLine()) != null) { process(str); } in.close();
(grazie a javaalmanac.com per lo snippet.) A prima vista niente di strano; le operazioni di I/O sono incapsulate nelle classi di java.io in perfetto amore object-oriented. Eppure questo frammento racchiude una serie di decisioni: e se io non volessi più usare il BufferedReader? E se volessi specificare un encoding? E se volessi testare senza toccare il filesystem? Sarebbe meglio incapsularlo in un modulino:
MyReader in = new MyReader("infilename"); while (in.hasNextLine()) { process(in.nextLine()); }
o anche
MyReader in = new MyReader("infilename"); in.eachLine(process);
Questo per dire che non sempre è facile riconoscere la duplicazione ed eliminarla.
The DRY (Don’t Repeat Yourself) Principle states:
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
che può essere espresso anche come
Each and every declaration of behavior should appear OnceAndOnlyOnce.