Sobes.tech
Senior

What is DCI?

sobes.tech AI

Answer from AI

DCI (Data-Context-Interaction) is a design pattern that separates business logic into three components: Data, Context, and Interaction, to improve readability and maintainability of OOP code, especially when working with changing requirements.

  • Data: Objects representing the subject area, containing only state (attributes). They do not contain business logic.
  • Context: The entry point for a use case scenario. It links data objects with their roles within a specific interaction, using their "role methods".
  • Interaction: The business logic of the use case scenario, implemented as a set of roles and their methods. It is a behavioral aspect of the system that "overlays" on data objects. Often implemented through mixins or traits that dynamically add behavior to data objects within the context.

The main idea of DCI is to make the developer's intentions, related to executing a specific use case, explicit in the code. Business logic is not tightly bound to data classes, allowing the same object to play different roles in different scenarios.

Advantages:

  • Improved readability and understanding of the scenario's business logic.
  • Reduced coupling between data classes and behavior.
  • Easier maintenance and modification of existing scenarios.
  • Preservation of data objects' purity (Model in MVC).

Concept example: An Account object can play the role of Source when transferring money and the role of Recipient when receiving money. The transfer logic (deduct from source, add to recipient) is located in the context of transfer, not tightly inside the Account class.

// Concept: Role TransferSource
const TransferSource = {
  decreaseBalance(amount) {
    if (this.balance < amount) {
      throw new Error("Insufficient funds");
    }
    this.balance -= amount;
  }
};

// Concept: Role TransferDestination
const TransferDestination = {
  increaseBalance(amount) {
    this.balance += amount;
  }
};

// Concept: Context - Transfer
class TransferContext {
  constructor(sourceAccount, destinationAccount, amount) {
    // Binding roles to data objects
    Object.assign(sourceAccount, TransferSource);
    Object.assign(destinationAccount, TransferDestination);

    this.source = sourceAccount;
    this.destination = destinationAccount;
    this.amount = amount;
  }

  execute() {
    // Using role methods
    this.source.decreaseBalance(this.amount);
    this.destination.increaseBalance(this.amount);
    // Additional context logic: logging, transactions, etc.
  }
}

// Usage example:
// Assume data objects (regular JS objects)
const accountA = { name: "Account A", balance: 100 }; // Data
const accountB = { name: "Account B", balance: 50 };  // Data

try {
  const transfer = new TransferContext(accountA, accountB, 30); // Context
  transfer.execute(); // Interaction (defined within Context using Roles)

  console.log(accountA.balance); // 70
  console.log(accountB.balance); // 80
} catch (error) {
  console.error(error.message);
}

Although DCI is not a common or widely used in standard frontend frameworks, its principles can be useful when structuring complex business logic, separating it from simple data objects.