Hi Yves,
Thanks for the awesome question! Achieving a flexible software architecture is something that we expressly designed Stanza for, and something I am personally very passionate about.
We strongly advocate adopting a layered software architecture when coding in Stanza. (Actually, we advocate a layered architecture when coding in any language, but Stanza was designed to make it easy.) In a layered architecture, developers partition their software into separate layers of abstraction. Each layer presents its own API, and is responsible for abstracting away some detail of the machine. The lowest layer will be concerned with how to shuffle bytes around in memory, and how to interface with external peripherals. The highest layer will expose almost no details of the machine, and instead be concerned only with business requirements. Each layer can access the API of the immediate layers below it, but may not "skip a layer".
Within an individual layer, developers will think about their software architecture as comparised of a set of 'things', along with defined relationships between those 'things'.
As an example, consider the architecture of a spreadsheet program (like Microsoft Excel).
A low-level layer may concern itself with details of file management and input devices. The 'things' that this layer manages are mice, keyboard, files, directories, etc. These would be modeled as types in Stanza:
deftype Mouse
deftype Keyboard
deftype File
deftype Directory
The relationships between these things are represented as functions that operate upon these types:
defn get-x-position (m:Mouse) -> Int
defn get-y-position (m:Mouse) -> Int
defn make-directory (s:String) -> Directory
defn contains? (d:Directory) -> File
...
Another layer may concern itself with the GUI event loop, and the details of how to draw widgets to the screen:
deftype Request
deftype RepaintWindowRequested <: Request
deftype ResizeWindowRequested <: Request
deftype ButtonClickRequested <: Request
deftype Shape
deftype Circle <: Shape
deftype Rectangle <: Shape
deftype Line <: Shape
deftype Window
deftype Button
defn draw (w:Window, s:Shape) -> False
defn handle-request (w:Window, r:Request) -> False
defn intersects? (s1:Shape, s2:Shape) -> True|False
...
And the highest abstraction layer will concern itself with objects that the user directory deals with:
deftype Project
deftype Formula
deftype SpreadsheetCell
deftype Cell
deftype NumberCell <: Cell
deftype NameCell <: Cell
defn evaluate (f:Formula) -> Int
defn store (c:Cell, f:Formula) -> False
defn clear (c:Cell) -> False
defn make-project (name:String) -> Project
defn save (p:Project) -> False
...
More importantly, notice what is not specified: the location of the functions. In a traditional OOP language, the location of each function is a big part of the program architecture. Should handle-request be a method in the Window class? Or should it be a method in the Request class? Or should it be a stand-alone function? Or should it be a method of a third RequestHandler class? Our belief is that these questions are ultimately not important, and serve only to detract from real architectural decisions: what are the things in the program, and what are the possible interactions between them.
An architectural document consists of an exhaustive listing of all the types in the program, and a description of all the interactions between those types. I used such a document to describe the implementation requirements of a just-in-time compiler in the graduate course that I taught, and it worked wonderfully. By the end of the course, we had thirty students successfully implement a just-in-time compiler from scratch, and ... they all behaved the same. So that we actually prepared a suite of benchmark programs and had the students compete against each other on the speed of their compiler.
Regards,
Patrick