deat v0.0.1
Deat
⚠️ Beta Version: This project is currently in Beta. Use with caution in production.
Description
Deat is a TypeScript library designed to model and manage runtime feature-oriented dependencies. It provides a flexible and powerful way to organize structured dependencies at runtime, allowing developers to create complex dependency graphs with ease.
Think of it as how NPM uses package.json to manage build-time dependencies, but for runtime.
Key Features
- Runtime Dependency Management: Manage structured dependencies at runtime with type safety
- Feature Composition: Compose features through dependency chaining
- Isolation: Keep dependencies isolated while allowing controlled sharing
- Flexible Architecture: Supports various dependency patterns and use cases
Background
Feature and Feature-Oriented Design
In the context of Deat, a feature refers to a minimal business unit exposed to users. Typically, building a feature involves implementing data structures and computation logic, then integrating them into a framework so they can be recognized and utilized.
A common challenge in this approach is that dependencies required for a feature are often scattered across multiple locations in the codebase rather than being centralized. This results in an implementation-oriented code structure, which can make complex applications difficult to understand due to high cognitive load. Additionally, encapsulating and reusing dependencies effectively may not be straightforward.
This is where Deat comes in. The name Deat stands for Dependency + Feature. It introduces a feature-oriented way to build features—by organizing and composing all structured runtime dependencies in one place, making dependency tracking much simpler and more modular.
runtime dependencies
Runtime dependencies refer to all the data and variables that need to be fed into an underlying framework or system to enable feature functionality.
dependency builder
A dependency builder is a function that returns the data structures required for a feature. Its parameters consist of dependencies injected by a Deat instance.
Problem It Solves
- Define and manage runtime dependencies
- Compose features through dependency chaining
- Maintain isolation while allowing controlled sharing
- Handle complex dependency scenarios with ease
Use Cases
- Feature-oriented architectures
- Plugin-based systems
- Runtime dependency injection
- Complex application composition
Installation
To install the project, run
yarn install deat
Usage
Here is a example of how to use the Deat
class:
import { Deat } from './src/index';
// Create a new Deat instance
const deat = Deat.create(
{ foo: 'foo', bar: 'bar' },
(deps) => {
// Extract all data from deps and compose them into a structured format required by the feature
return { feat: [deps.foo, deps.bar] };
},
// (Optional) Provide an existing Deat instance as peer dependencies
peer
);
// Build a Deat instance to output feature-oriented data
const output = deat.run();
console.log(output);
// Append new dependencies and a builder to the current Deat instance, returning a new instance
const deat2 = deat.append(
{ baz: 'baz' },
(deps) => {
return { feat: [...deps.feat, deps.baz] };
}
);
// Append new dependencies without a builder, returning a new Deat instance
const deat3 = deat.appendDeps({
baz: 'baz'
});
// Append a new builder without adding dependencies, returning a new Deat instance
const deat4 = deat.appendBuilder((deps) => {
return { feat: [...deps.feat, 'qux'] };
});
// Chain two Deat instances. Later instances can use all previous dependencies and builder outputs.
const chain = deat.chain(deat2);
// Merge two independent Deat instances. Their dependencies and builder outputs remain isolated during execution, but the final results are merged.
const union = deat.union(deat2);
// Update a dependency in a Deat instance
const updated = deat.update("foo", "bar");
Internal
Internally, a Deat instance is implemented as a linked list that tracks dependencies and builders. Each node in this list stores dependencies and their corresponding builder. When calling deat.run(), Deat processes each node in order, injecting all previously computed dependencies into the current one.
In some cases, you may want to merge two independent Deat instances while keeping them isolated during execution (i.e., parallel execution instead of serial execution). This can be achieved using deat.union().
When merging instances via union(), Deat identifies each node by its UUID and groups nodes with the same header ID into separate build lists. If multiple nodes share the same UUID, Deat eliminates duplicates and reuses a single node across multiple lists.
Testing
To run the tests, use:
yarn test
5 months ago