Relationships with Traditional OOA
The best practices of traditional OOA/D are well defined in Catalysis. However, Catalysis makes certain distinctions that clarify issues that have remained unresolved in traditional methods. If you are experienced with an existing method, here are some things to be aware of (you will find more details in the FAQ):
Abstraction, Precision, and Deferred Decisions
All good methods attempt to support abstraction. Catalysis, however, takes the position that abstraction too often equates to fuzzy, ambiguous, and unreliable; and aims to make even abstract models precise enough to be the basis for traceability and testing. The specific kinds of abstraction supported effectively separate decisions that are best deferred. Through all this there is still a focus on the language of the client, and techniques to make the models closely match the client's understanding and natural expression of the problem.
Refinement and Fractal Modeling
The idea of refinement is central to Catalysis, and notably lacking from the most popular OOA/D methods (Fusion and Syntropy are notable exceptions). It lets you make very clear separations between abstract descriptions and particular ways of realizing them; yet it supports traceability and testing in a way far more concrete than the naive OOAD view of "model the domain and elaborate into your code". In particular, it makes fractal modeling practical, so the same techniques are used at all levels without any loss of precision or generality. We model a software system, corporate department, and Java object using the same techniques; and similarly for a business task, system use-case, and Java message.
Deferred Localization of Behavior
Traditional OOA/D approaches assign behaviors to classes very early in the development process, and consequently lose sight of the overall system behavior. Jacobsen's use-case approach somewhat rectified this by stepping back to the user-tasks and then working out the software object interactions to realize that task. What it missed, however, is the power of a uniformly fractal approach based upon refinement.
Traditional OOAD methods (OMT, Booch, Objectory) have focused on the class as the main unit of modeling, often mixing implementation concerns (sharing of data members and method bodies) with specification concerns. This is a well recognized shortfall of traditional OO languages as well, rectified in languages like Java by explicit separation of interfaces from implementation constructs.
Catalysis can correctly be considered an interface-centric approach to component and object development. Types model interfaces abstractly, yet precisely (using attribute models and action refinement), and tests specified against interfaces apply independent of the implementation. Collaborations model sets of related types and their roles in interactions - precisely the basis of design-patterns. Collaboration composition allows us to build designs by composing fragments of design or architectural patterns that are also interface-based. And the pluggable-framework approach to code gives us alternate mechanisms to using this approach in the implementation as well.
Frameworks and (entire) model inheritance
Catalysis frameworks are expressive enough to model specification patterns, patterns of attributes and invariants, patterns of generic classes, collaboration and design patterns, and even patterns of methods and instance variables in code. They capture the key part of such patterns: the relationships between the parts that hold even as the individual parts themselves are specialized or substituted for.
Attributes vs. Instance Variables
Catalysis makes a strong distinction between an attribute modeled on a type, and an instance variable stored in a class. Attributes abstract stored data; the key questions to ask when modeling an attribute are:
This very simple idea provides immediate benefit at every level:
Once you understand that model attributes do not have to be directly stored, but may be computed instead, it is a simple step to understand parameterized attributes. Just as it is reasonable to model the price of a product as an attribute of Product, so also we can model the price (for a particular quantity) of a product as a parameterized attribute: Product. price_of (quantity): $. What we are doing here is saying that there are potentially many different prices for different quantities of products, deferring the details of a specific quantity-based pricing policy without any loss of precision.
Why not model these as operations? Because, in Catalysis the fundamental distinction is between abstraction of state (attribute) and abstraction of behavior (action). An attribute, whether parameterized or not, is an abstraction of state; attributes are related to other attributes by static invariants, while actions are specified by postconditions.
Design vs. Specification Types
When modeling, there are some objects whose behavior is of primary importance (e.g. a PrintSystem at the analysis level); and others that help to structure the description of its attributes and behaviors (e.g. a PrintJob may be a useful way to conceptualize and make precise the behavior of the PrintSystem, but it may never actually exist in an implementation). In Catalysis these two uses are referred to as Design Types and Specification Types. Design types will have actions of interest, while specification types will often only have attributes (and, optionally, effects).
How do we describe "responsibilities" in Catalysis? There is a surprisingly crisp answer, allowing us to use responsibility-driven design and support it with precise models whenever appropriate:
Views and Multiple Specs
There is no need for a model or specification of an object type to say all there is to be said about that type in a single diagram or piece of text. In fact, most complex models are best broken into parts (views, or subject areas); and different aspects of the same objects and actions are described incrementally in those subject areas. This makes the models and documentation more maintainable, since you could locally change certain aspects (e.g. performance, concurrency, logging) without editing the contents of the others.
Use cases are a perennial favourite, and are strongly supported in Catalysis. We do make some critical distinctions and clarifications about the different between the abstract use-case itself, the sequence of finer-grained use-cases that realizes it, and the meaning of <<include>> and <<extend>> relationships.