XDbC / eXplicit Design by Contract™
Leverages the explicit nature of metadata to provide a
Design
by
Contract™ Framework in a precise and comprehensible manner.
| Do... | Instead Of |
|-------------------|------------------------------------------------------------|
|
@DBC.ParamvalueProvider
public method(@AE.PRE([new REGEX(/^\.XDBC.\$/i)]) input : Array\) {
...
}
|
public method( input : Array\) {
input.forEach(( element, index ) => {
console.assert(/^.\XDBC.\$/i.test(element),"inconsistent error message");
});
...
}
|
@REGEX.INVARIANT(/^.\XDBC.\$/i)
public field = "XDBC";
|
get field() : string { return ... }
set field( toSet : string ) {
console.assert(/^.\XDBC.\$/i.test(element),"Inconsistent error message");
...
}
|
@REGEX.POST(/^XDBC$/i)
public method( input : unknown ) : string {
...
return result ;
}
|
public method( input : unknown ) : string {
...
if(!/^.\XDBC.\$/i.test(result) {
throw new Error("inconsistent error message");
}
return result ;
}
...and get consistent details about errors like: [ XDBC Infringement [ From "method" in "MyClass": [ Parameter-value "+1d,+5d,-x10y" of the 1st parameter did not fulfill one of it's contracts: Violating-Arrayelement at index 2. Value has to comply to regular expression "/^(?i:(NOW)|([+-]\d+[dmy]))$/i"]]]
What is Design by Contract™ ?
Design by Contract™ (DbC) is a software development approach focused on defining precise and verifiable contracts between software components. These contracts specify the preconditions that must be true when calling a component (e.g., a function or method), the postconditions guaranteed after the component's execution, and the invariants that must hold true throughout the lifetime of an object or class.
Benefits of Design by Contract:
| Benefit | Description |
|-----------------------|------------------------------------------------------------|
| More Reliable | Early error detection through contract checking |
| More Maintainable | Clear responsibilities and expected behavior |
| Better Documentation | Contracts as living behavior descriptions |
| Easier Debugging | Error causes traceable through contract violations |
DbC improves software quality and maintainability by explicitly defining and verifying contract conditions.
What is the difference between DbC and Assertions ?
| Feature | DBC with Decorators | Assertions |
|------------------|----------------------------------------|---------------------------------------|
| Formality | Formal, explicit in definition | Informal, often within the body |
| Integration | Metadata | Built-in keyword |
| Features | Can be more feature-rich | Simple, primarily for error detection |
| Readability | Generally good, contracts are clear | Can become cluttered |
| Maintainability | Often better, contracts are localized | Can be harder to track and modify |
| Production | Contracts can be kept or disabled | Often disabled for performance |
Demo & API Documentation
Check out the
Demo.ts to see some examples usages and the
API's documentation.
Installation
``
sh
npm install --save xdbc
``
Usage
As by now there're 14 contracts that can be used:
- AE (
Each element of the value-array has to fulfill a certain set of contracts)
- EQ (
Value has to be equal to a supplied reference value)
- COMPARISON (
Value has to be greater, less, greater/equal, equal or less/equal than a supplied reference value)
- INSTANCE (
Value has to be an instance of a supplied type)
- JSON.OP (
Value has to contain certain properties of certain type)
- JSON.Parse (
String-value has to be a parsable JSON)
- OR (
At least one of a set of contracts has to be fulfilled)
- REGEX (
Value has to be validated by a supplied regular expression)
- TYPE (
Value has to be of a certain type)
- GREATER (
Derived from COMPARISON)
- GREATER_OR_EQUAL (
Derived from COMPARISON)
- LESS (
Derived from COMPARISON)
- LESS_OR_EQUAL (
Derived from COMPARISON)
- DIFFERENT (
Derived from EQ)
All of which expose a method
PRE,
POST and
INVARIANT (
precondition, postcondition and invariant).
Import the classes to use from
xdbc. If parameters shall be decorated with contracts import class
DBC also.
The
PRE-Method can be used to decorate method-parameter:
public method(@REGEX.PRE(/XDBC.\*/g) input : string).
Whenever the method is invoked the value will be checked. Since parameter decorators don't have access to the parameter's value, the method itself must additionally be decorated with the
ParamvalueProvider:
@DBC.ParamvalueProvider
public method(@REGEX.PRE(/XDBC.\*/g) input : string)
The
POST-Method can be used to decorate a method:
@EQ.POST(10)
public method() { return 10 ;}
Whenever the method returns, it's return-value will be checked.
The
INVARIANT-Method can be used to decorate fields:
@REGEX.INVARIANT(/^a$/)
public testProperty = "a";
Whenever the field is assigned a value and also when initialized, the new value will be checked. So there's no need to write a getter and setter just because there's is the necessity to perform checks on the value anymore.
Certain contracts take other contracts as a parameter. For example the
AE contract that applies a specified set of contracts on each element of the tagged object's value if it is an array or the object itself if it isn't:
@AE.PRE([new REGEX(/^(?i:(NOW)|([+-]\d+[dmy]))$/i, new GREATER(10,"length")]).
With
PRE,
POST and
INVARIANT decorators an optional
path parameter may be specified. This parameter is a dotted path to a nested property of the tagged object that shall be checked instead of the tagged one. Thus
@DBC.INVARIANT([new REGEX(/^.$/)]) could also be defined as:
@DBC.INVARIANT([new EQ(1)],"length"), that way demanding that the value to be set is a string with exactly one character.
Multiple instances of the class
DBC with varying settings for e.g. reporting infringements may be instantiated. Which of these instances is used to report can be defined when either using
PRE,
POST or
INVARIANT by defining their
dbc parameter:
@DBC.INVARIANT([new EQ(1)],"length","MyVendor.MyDBCInstance"), for example. The standard path (
WaXCode.DBC) leads to an automatically created instance, that is generated when the Framework is imported.
Many contracts got further features like the
AE-Contract that can check specific ranges within the tagged array or the
EQ--Contract that can be inverted turning it into
not EQual-Contract. Check out the
API for details.
A
DBC's
warningSettings &
infringementSettings determine what happens on warnings and errors, whereas warnings are not implemented yet.
DBC can be turned off for
PRE-,
POST-Conditions and
INVARIANTS separately by setting the proper
executionSettings of the
DBC-Class.
Contribution
Participation is highly valued and warmly welcomed. The ultimate goal is to create a tool that proves genuinely useful and empowers a wide range of developers to build more robust and reliable applications.