blob: e6b85d4bb9e7347fe7d8b562aa487b4664fe4401 [file] [view]
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Why
We have Jira/TAPD for **Project Management**, we have Github/Gitlab/BitBucket for **Code Hosting**, that is, we have
multiple _Platforms_ for a certain type of problem. So, how can we calculate metrics across different _Platforms_?
For example, some users may use Jira as their **Project Management** platform, the others might opt for TAPD, if we
were to implement a Requirement Count metrics for all users, should we implement 2 charts for Jira and TAPD
independently? It's too impractical to begin with.
# How
Domain Layer is designed to solve the problem by offering a set of Platform Independent Entities, Devlake divides all
platforms into three categories: Project Management / Code Hosting / Devops, by abstracting common properties from
different platforms, we can define a set of Domain Entities for each category.
The following rules make sure Domain Layer Entities serve its purpose
1. Every platform specific entity can be mapped (or split) to one (or more) Domain Layer Entity
2. Every Domain Layer Entity contains enough information for metrics calculation
3. Domain Layer Entity should contains some sort of pointer to its origin record, and all entities should share a same
schema
# What
## Domain Layer Entity
- Each **Domain Entity** has a `Id` with type `string` describe its origin record in format
`<Plugin>:<Entity>:<PK0>:<PK1>`, because:
1. Different platforms might choice different types as their Primary Key, i.e. `AutoIncremental Integer` or `uuid`
2. Platform might or might not use `composite primary keys`
3. Primary key might overlay between entities, and multiple entities most likely will be combined into one table
4. Different plugins might use same entity name, even they can not co-exists at the same time, so plugin name must
be
included for distinction
5. This format is deterministic, each of every entity can be converted independently in parallel, and data could be
rebuilt arbitrary time with same output, which mean you can truncate any table at any time, and data integrity
will be restored on next run. (this is not possible for `AutoIncremental Integer` or `uuid`)
- Each **Domain Entity** must contains enough fields needed for all metric calculations
## Data Conversion
- Read data from platform specific table, convert and store record into one(or multiple) domain table(s)
- Generate its own `Id` accordingly
- Generate foreign key accordlingly
- Fields conversion
Sample code:
```go
type Issue struct {
Id string `gorm:"primaryKey"`
BoardId string `gorm:"index"`
...
}
issue := Issue {
Id: "jira:JiraIssues:1:10",
BoardId: "jira:JiraBoard:1:10"
...
}
```