Achieving Architecture Goodness

Last Updated September 17, 1999 - Jack Harich - Go Back

"If I had eight hours to chop down a tree, I'd spend six sharpening my axe." - Abraham Lincoln


Quick Overview

Our goal is to be able to guarentee we have a really good architecture. This requires a rigorous repeatable process, in addition to experience and judgement. Basically we determine Requirements and then test several Candidate Architectures (or architecture portions) to see which are better. Since good designers generate alternate solutions paths, the process gives good feedback on which path is better, and how good a path is. This provides quick, deep understanding of the fundamental decisions the architects should focus on, which leads to better decisions, which allows the architects to iteratively zero in on an optimal result. We use the definition:

Architecture is a system's high level structure, which consists of components, their responsibilities and their relationships.


The Process

Architecture is a subset of an entire system, and so takes a different process from systems to do well. Hence we do not use the entire Mini Process, but just a similar set of steps. Briefly, the process is:

  1. Determine Requirements
    1. Nutshell vision
    2. Narrative describing what system should do
    3. Key traits
    4. Key use cases
    5. Key possible future traits and use cases
    6. Key architecture dependent risks, such as performance
    7. Organize key requirements into grid with rankings
  2. Validate Requirements (Are we building the right thing?)
    1. (to be designed)
  3. Design Architecture
    1. Generate candidate architectures (hard)
  4. Verify Architecture (Are we building it right?)
    1. Do prototypes as necessary
    2. Use prototypes to improve requirements and architecture
    3. Evaluate architecture against key requirements
      1. How well does candidate meet requirements?
      2. What modules need changing to meet requirements?
      3. How easy are changes to make?
      4. What is likely defect rate of a change?
    4. Analyze evaluation results, do totals
    5. Decide relative merit of candidates

Please note that architecture is high level only, not a system's complete design. This is why we can use just key requirements, and zoom right along with a lightweight process. It's the 80/20 rule.

Much of this is based on the book "Software Architecture in Practice" by Bass, Clements and Kasman, 1998, from the SEI. This is the best book on software architecture I've seen. Chapters 1, 2, 4 and especially 9 are what I found most useful.

A weak point is "Generate candidate architectures". All this process does is use Requirements to test architectures. Creating an architecture still takes "a rather good eye". However, if the Requirements are correct, one can at least determine if an architecture is sufficient. There's also the high probability that a better architecture will evolve due to the evaluation feedback loop, and deeper understanding of the architectures and their common patterns. For a few suggestions see Modeling Checklist and the superb book mentioned above. The greatest single suggestion we can make is, "Good architecture is based on good principles".


An Example

Since a picture is worth a thousand words, we jump right into an example. Naturally we use a current project - The second generation of the UHR reference implementation core.


Determine Requirements


1. Nutshell Vision

Create a second generation UHR reference implementation, using the lessons learned from the BA. It should be so good it lasts at least 2 years before replacement, with Parts good for 3 years or more and DK good for 5 years or more.


2. Narrative

See the User's Mental Model for a fresh and concise description.

This architecture covers only the "core" technology, previously called the microkernel. The core should be a good lower layer for parts and visual tools, so core architecture must provide good collaboration abilities with higher layers.


3. Key Traits

Top goals here are:

  1. High expressiveness - Ability to handle any design or domain
  2. Low solution time - Time to market
  3. Low short term solution cost
  4. Low long term solution cost
  5. Sufficient performance

Subgoals that go under one or more of the above are:

  1. High reliability
  2. Good testability
  3. Ease of modification - Modifyability
  4. Ease of learning
  5. Ease of use
  6. Ease of independent module development
  7. High reuse of in house modules
  8. High reuse of market modules

Note how these are domain independent, and thus reusable. Perhaps that's because UHR is basically a framework for frameworks, ie a meta framework. In UHR a module is a part, which can be a container of parts or a leaf part.


4. Key Use Cases

These are domain dependent. Our key actors are Business, Core Tech, Part Shop, Assembler, End User and Part. This choice of actors reflects a "part flow" production process, a design decision in itself.

Our first pass lists important cases. We shall see which are architecture dependent and really are key cases.

Business

  1. Evaluate UHR core and other items for possible adoption.
  2. Start simple and ramp up for easy Technology Transfer
  3. Train engineers and others in use of new technology.
  4. Make investment decisions in strategic parts inventory.
  5. Make investment decisions in UHR based products.

Core Tech

  1. Manage the companywide process of using UHR.
  2. Design parts inventory strategy.
  3. Create domain frameworks.
  4. Create strategic or difficult parts.
  5. Produce in house tools using UHR.

Part Shop

  1. Evaluate part feasibility request.
  2. Create a part.
  3. Create a suite of parts that use a framework.
  4. Evaluate part enhancement request.
  5. Do part enhancement.
  6. Fix part defect.

Assembler

  1. Evaluate system feasibility request.
  2. Design system tree.
  3. Assemble system from parts.
  4. Evaluate enhancement request.
  5. Do enhancement.
  6. Fix defect.
  7. Document system for in house use.
  8. Document systemn for end user.
  9. Understand an old system someone else created.

End User

  1. Start a system.
  2. Close a system.
  3. Customize a system.
  4. Build a system from scratch.
  5. Update parts automatically while system is running.

Part

  1. Receive initial DK.
  2. Apply new DK while running.
  3. Receive Message.
  4. Send Message.
  5. Get a part instance for direct use.
  6. Use core for mutator special use.


5. Key possible future traits and use cases

In addition to these, we list possible future Use Cases, to test Modifyability. This is an extremely useful way to discover architectural weaknesses. A "Core Part" includes non-parts such as the Part interface in Candidate Architecture 2.

  1. Add more node types besides Container or Leaf Part.
  2. Support "web structure" rather than just tree.
  3. Change a core part substantially.
  4. Change the entire core substantially.
  5. Replace any core part while running.
  6. "Heal" any part while running if in trouble. (not clear)
  7. Do not use Messages at all for ultra high performance.
  8. Do not use DK for various reasons.
  9. Create a super tiny core for embedded use.
  10. Support transactions in the core.
  11. Port to C++ for performance reasons.
  12. Use code manglers for security reasons.
  13. Allow entire branches or systems to migrate to another location.
  14. Scale up to 100,000 nodes.
  15. Support virtual nodes, such as container fascade to another system.
  16. Handle multi-threaded work.
  17. Load classes, DK, images, etc from server database.
  18. Generate systems from systems.
  19. Support GUI drag and drop Visual Tool.


6. Key Architecture Dependent Risks

x


7. Organize key requirements into grid with rankings

x


(to be continued)