Catalysis is based on a set of principles about software development. These will be discussed in some detail here.
The only way we can handle complexity is by avoiding it. Selectively, that is. We focus on aspects that are important to our perspective, and ignore all others. You abstract when you publish an interface without exposing its implementation; or describe an abstract action without drilling down to the interaction protocol beneath it. Other significant abstractions include requirements - what must be done, not how it gets done; and architecture - large grained structure and relationships rules and constraints, not the detailed design. There is nothing theoretical or academic about abstraction; effective software development demands it.
Do developers use precise or formal methods? Surprisingly, the answer is yes. In code. Code is about as precise as you can get; you can't hand-wave at the compiler, or tap-dance your way around its error messages.
Yet, when it comes to more abstract descriptions we are very accustomed to being fuzzy and imprecise. Both hand-waving and tap dancing come in handy a bit too often.
This is probably why "abstract" is often equated with fuzzy, imprecise, or unreliable. Often, "requirements" are described so poorly and inconsistently that is becomes impossible to determine whether a given implementation meets that requirement or not. Similarly, the term "architecture" is often used to grace a prettily laid out set of boxes and lines on a PowerPoint slide; but no one can really determine whether a given design conforms to that architecture. As a result, a clear shared understanding becomes difficult; the validity of these abstractions is very hard to ascertain (and maintain); and you cannot validate implementations against them.
This need not be so.
Abstraction is a wonderful and valuable thing. However, abstractions in which the meaning of that abstraction is very fuzzy, so that a team of people will likely walk away with different interpretations, loses a lot of that value. In Catalysis we believe that the most useful abstractions should be at lease precise enough to be refuted i.e. if you give me a specification of some services (an abstraction), and I return with the code (an implementation), the abstraction should be precise enough for you to show me (via tests, examples, inspection, or argument) the error of my ways i.e. to refute the abstraction.
Abstractions are fine; but they must have realizations. How are these two related? By the key concept of refinement. Each refinement may have associated with it a justification (which helps map from the realization to the abstraction); tests (to verify that an implementation is correct with respect to that abstraction); architecture (to define the standard structures and patterns used in the realization).
Should Models be Executable?
Some say yes, others say no. The reasoning behind this is actually quite interesting, particularly in the world of component-based development -- where you often want to abstract away details and provide multiple, increasingly abstract views and interfaces to some implemented behavior.
Very little development work is entirely unique. When modeling, when you draw two boxes and connect them with a particular kind of line, someone else has done something very similar, with the same intent as you (in a different context, admittedly). So, why don't we simply define Two_Boxes_with_Line construct once, and then use it as a pluggable model part? Similarly, other kinds of patterns recur in business models, system specifications, architectures, and code.
We would like all development work to be done by putting together units from an extensible set of reusable parts.
Conservation of Pain
For every project there is a certain minimum amount of pain that will be encountered, regardless of how you do that project. This is the law of conservation of pain. The approaches and routes that get over that pain earliest in the development cycle tend to minimize the overall cost of that pain.
Also known as: Expose Issues Early.
Minimize the Magic
There is often too much "magic" in development. This magic shows up in large gaps between the descriptions between business process, software solution, and technical infrastructure; or in the mysterious ways some design elements become invented by the gurus and just work well; these are often things which no one can quite explain.
Over time and across projects, you want to minimize the magic that happens in a development process. One way to do this is to capture known designs, techniques, processes, architectures; to establish a common vocabulary across business, analyst, architect, programmer; and to use common core techniques for requirements, non-functionals, specs, and design.
And while there is no way to bottle up creativity, careful thinking, and insights, we can at least minimize the magic.
Don't reuse code without reusing the specification of that code.
Once and only Once (Kent Beck)
If there is anything important you need to say (in your model, design, or code), make sure you say it once, and only once. Specifically, if there is a term that is very natural for the client to use to describe some rule, constraint, or behavior, make sure that you introduce this term into your model and define it. Use the introduced term every place else you need to, so you don't redundantly describe it separately elsewhere.
The same rule at the level of code is one of the tenets of Extreme Programming.