Skip to content

Commit

Permalink
✨feature: add more contents (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
halajohn authored Aug 29, 2024
1 parent 63d13f3 commit ee8721c
Show file tree
Hide file tree
Showing 3 changed files with 304 additions and 0 deletions.
2 changes: 2 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

## TEN framework

* [Goal](ten_framework/goal.md)
* [Version system](ten_framework/version_system.md)
* [Testing](ten_framework/testing.md)

## TEN Service
Expand Down
239 changes: 239 additions & 0 deletions ten_framework/goal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# Goal

Modularity is a cornerstone of robust software design, offering numerous advantages including simplified maintenance, enhanced scalability, and increased development velocity. To fully leverage these benefits, the platform must provide comprehensive mechanisms to foster the implementation of best engineering practices for modular develop.

Modularity is a cornerstone of robust software design, offering numerous advantages including simplified maintenance, enhanced scalability, and increased development velocity. To fully leverage these benefits, the platform must provide comprehensive mechanisms to foster the implementation of best engineering practices for modular development.

## Modularization

1. Defined Module Boundaries

Including boundaries for the control plane and data plane, which can be declared statically, facilitating inspection and post-processing of offline tools.

2. Dynamic Service Composition

The number and type of modules contained in a process can be determined at runtime, without the need to statically determine it during compilation.

3. Streamlined Module Integration

In scenarios with multiple module compositions, it is desirable to require only declarations without modifying any code in the modules, and ideally, without even writing glue code to combine different modules.

4. Decentralized Module Coupling

In the architecture, there is no coupling between modules, allowing different modules to be developed by different individuals and development teams, and they can be dynamically replaced.

5. Flexible Module Interface Communication

The interface invocation between modules needs to have two types. One type requires the parameters of the invocation to be consistent on both sides, such as parameter names, types, etc. The other type allows the parameters of the invocation to be different on both sides, such as different parameter names and types, but the platform provides mechanisms to bridge the invocation on both sides. This second type is an important foundation for the independent development and deployment of modules.

## Orchestration

Once the modules are successfully separated, they need to be combined to create a truly functional service. Therefore, the architecture needs to provide sufficient mechanisms to flexibly and easily compose multiple modules into a service. This composition should be highly adaptable, even in cases where the module source code is unavailable, enabling the modules to be combined with great flexibility.

1. Directed Cyclic Graph (DCG) Topologies

The composition between modules supports not only single-line pipeline topologies but also arbitrary graph structures that are independent of each other in the control plane and data plane. This includes 1-to-n, n-to-1, and n-to-m interaction relationships.

2. Cross-Process and Thread Orchestration

Coordinating module instances running in different processes and threads to form a final service scenario.

3. Dynamic Orchestration Configuration

Orchestration can be dynamically issued during runtime or pre-configured within the service before it runs.

## Flexible Configuration Settings

Each instance of a module needs to have a method for independent configuration, where the configurations can be set either before runtime or dynamically during runtime or even distributed as configuration updates.

1. Hierarchical Configuration Support

Architecturally, different instances of modules may have different configuration possibilities, and the configuration possibilities may also vary across the hierarchical context of running modules.

2. Versatile Configuration Capabilities

Configurations can be pre-set before runtime, dynamically changed during runtime, or even distributed during the execution process.

## Diverse Releasing Capabilities

Some modules may prefer not to open-source their codes. Therefore, the architecture needs to allow the full utilization of these modules' functionalities, even without accessing their source codes. This includes the ability to integrate these modules to form a larger and more comprehensive service.

1. Support Binary & Source Release

Modules support source distribution and binary distribution, and both distribution modes can coexist for the same module.

2. Integration With Cloud Marketplace

Both source and binary distributed modules can be published on the cloud marketplace for developers to download and incorporate into their projects.

## Multiple Instances Capability

The flexibility of having multiple instances is always superior to the restriction of having only a single instance. Therefore, it is necessary to ensure, in the architecture, to support multiple instances in all aspects.

1. Multiple Instances of the Platform Itself

The platform itself does not use any global variables or employ any flawed designs that would prevent the external environment utilizing the platform from having multiple platform instances within a single business process.

2. Multiple Instances of Each Module

Architecturally, it should allow module developers to develop modules without relying on any global variables, enabling multiple instances of the same module within a process without conflicts. These different instances of the modules not only can run in the same thread or different threads, but they also can run within the same process or different processes.

3. Multiple Instances of the Orchestrated Pipelines

Within a single process, it is possible to include multiple orchestrated pipelines that can run concurrently in different threads or sequentially within the same process.

## Diverse Distribution Capability

Different modules can be deployed in different execution environments based on actual requirements. Furthermore, modules that run in these different environments need to have sufficient mechanisms in the architecture to facilitate their seamless integration or adaptation.

1. Dynamic Switching of Multiple Distribution Configurations

The service itself can be quickly split and distributed to different processes and threads to achieve module-level high availability and high concurrency, and it is easier to achieve hot-updating of modules after the application has been made.

2. Decoupling of Distribution Configuration From Code

When distributing modules across different processes and threads, it is preferable that the modules themselves do not require any modifications.

3. Decoupling of Distribution Configuration From Compilation and Build

The distribution of modules across different processes and threads should be accomplished through simple declarations.

## Flexibility Input/Output Support

The way modules handle their external input and output determines the flexibility of their arrangement and the possibility of achieving low coupling between them. Therefore, the architecture must provide sufficient mechanisms to enable input and output interactions between modules to achieve a high degree of decoupling. This greatly facilitates the flexible composition of multiple modules.

1. Supports Control Plane as well as Data Plane (audio/video/data)

The interaction between modules can involve invoking commands as well as passing raw audio and video data.

2. Simultaneous Support For Inter-process and Inter-thread Input/Output Patterns

Architecturally, within the same external input-output operations, supports module composition across processes and threads simultaneously.

3. The Essence of RPC

The module's external input/output needs to possess the essence of RPC, so that different modules can be placed in different processes and ultimately be combined into one scenario.

4. The Ability to Trigger Multiple Downstream Components

A single external action of a module can trigger operations in an unlimited number of downstream modules, and the platform will aggregate the responses from all downstream modules and return them to the original module.

5. Declarative Capability for External Input and Output

The external input and output interfaces of modules can be statically declared (in JSON or protobuf, …), which benefits the possibility of static checks in offline tools.

6. Simplifying the Writing of External Input/Output Codes

To enhance development efficiency, the external input/output interfaces need to support function calls, which facilitate the coding of the module itself. This function interface should be generated automatically by tooling as much as possible.

7. Supporting Data Types That Cannot be Serialized or Deserialized

The external interface of the module needs to support the transmission of data that cannot be serialized/deserialized. Offline tools can automatically recognize the usage of this transmission method and tag it to the metadata of the module, indicating that the module and other modules using it need to be in the same process.

8. Transparent Underlying Data Exchange for Inter-process Communication in Module

In the architecture, if the interaction between modules crosses processes, there is no need to worry about the underlying transmission logic and implementation (tcp/http/websocket/…). This aspect is handled entirely by the platform.

9. Support Synchronous and Asynchronous Control Plane Operations

The control plane has bidirectional interaction, allowing not only forward command sending but also corresponding response returns.

10. Support Restricted Execution Context

Architecturally, it enables synchronous interaction between modules that occurs within the same thread.

## Freedom in Developing Modules

The architecture must empower developers with the highest level of flexibility when developing modules, enabling them to create modules with unlimited functionalities and types.

1. Freedom to Utilize Third-party Library Functionality

Modules can utilize any third-party libraries to accomplish desired functionalities.

2. Freedom to Utilize Operating System Functionality

Developers should be given maximum freedom when developing modules, such as the ability to freely create and terminate native threads within the modules.

## Programming Language Support

Different development languages are more suitable for different scenarios. For example, Python is commonly used in AI scenarios, while C/C++ is often used in high-performance scenarios. Therefore, the architecture must support developers to develop modules using any programming language, and these modules developed in different languages should be well integrated within a service.

1. Unlimited Programming Languages Support

In the architecture, it must support all programming languages (C/C++/go/Java/Python/JavaScript/TypeScript/ruby/Perl/…), even if only a few programming languages are supported initially.

2. Modules Developed in Different Languages Can Run Together

Architecturally, it should allow modules written in different programming languages to run within the same process.

3. Unified Interaction Mindset Across Different Languages

The external interfaces between different language versions of the module have the same interface and behaviors, in addition to the language-specific aspects.

4. Unified Data Types Across Different Languages

The platform provides a unified data type across different languages, enabling modules written in different languages to have consistent thinking when exchanging data.

## Rich Capabilities for External Interaction

A service is only meaningful if it provides capabilities to the outside world. Therefore, in terms of architecture, it is necessary to empower modules to provide various capabilities to the outside through various standard methods.

1. UI Provider

In the architecture, as a backend service, it must support providing UI components for the frontend, even if this capability is not initially implemented.

2. RESTful Interface

As a backend service, it needs to support a RESTful interface, allowing clients to interact with it through RESTful methods.

3. Non-intrusive Integration with Existing Business

The architecture must support the ability to integrate the framework within existing services that have already been developed, rather than requiring the entire service to be rewritten using the framework.

4. The Whole Can Be in a Single Thread

In terms of architecture, it can exist as a standalone process or as a thread within an existing business service, and it will not conflict with the existing business code symbolically.

## Testing Friendly

One of the purposes of modularity is to facilitate more effective testing. Therefore, the architecture must support the ability to test each module independently.

1. Diverse Testing Mechanism

Architecturally, the platform supports multiple testing strategies, including unit test, integration test, module testing, and black-box testing.

2. Independent Module Testing

Architecturally, modules themselves can be tested independently.

## Offline Processing Capability

The architecture must support the use of offline tools to assist in development, as enhancing the development experience is a straightforward task.

1. Package Manager

In the architecture, it allows for CLI and the package manager to manage all modules and their combinations.

2. Orchestration Tools

There are GUI offline tools to facilitate the overall development and orchestration process, enhancing development experience and efficiency.

3. Visual Debugging Tools

In the architecture, there is the ability to create offline tools to visualize the interaction between modules.

## Robustness

The platform must possess high robustness in order to provide a favorable operating environment for all modules.

1. High Concurrency of Orchestrated Pipelines

A process can support the simultaneous execution of at least 100 concurrent instances of orchestrated scenes.

2. High Concurrency of RESTful Interface

A process can support over 20,000 RESTful clients.

3. High Concurrency of Non-RESTful Interface

A process can support over 1000 non-RESTful clients.
63 changes: 63 additions & 0 deletions ten_framework/version_system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Version System

The TEN framework follows the semver specification.

## Version Information of TEN Package

The version information of a TEN package is recorded in the `version` field of its own `manifest.json` file. For every TEN package, this `version` field is mandatory.

``` json
{
"version": "1.0.0"
}
```

## Version Requirement of Dependency

> ⚠️ **Note:**
> If no version requirement is specified for a dependency, the latest version is implied.
``` text
└── ten_packages/
├── extension/
├── extension_group/
├── protocol/
└── system/
```

These packages are distinguished by the value of the `type` field in their `manifest.json`.

``` json
{
"type": "system", // "extension", "extension_group", "protocol"
}
```

In a TEN package, the version requirements for the dependent TEN packages are specified as follows.

``` json
{
"dependencies": [
{
"type": "system",
"name": "ten_runtime",
"version": "1.0.1"
},
{
"type": "system",
"name": "ten_runtime_go",
"version": "1.0.3"
},
{
"type": "extension",
"name": "default_http_extension_cpp",
"version": "1.0.0"
},
{
"type": "extension_group",
"name": "default_extension_group",
"version": "1.0.0"
}
]
}
```

0 comments on commit ee8721c

Please sign in to comment.