# Group

## 架構

Packhouse所有的結構與方法都必須封裝在Group內，結構大概如下：

![](https://firebasestorage.googleapis.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LwD6MjHg3yMxWgKGDEI%2Fuploads%2FIrF1ZNXZLiicZuOrzoYW%2Ffile.png?alt=media)

## Property

[Mold](https://packhouse-doc.metalsheep.com/the-instance/group/mold)： 參數型別，可視為Interface或Type的功能。

[Tools](https://packhouse-doc.metalsheep.com/the-instance/group/tool)：方法(Function)的最小單元。

[Lines](https://packhouse-doc.metalsheep.com/the-instance/group/line)：柯里化(Curry)的結構宣告。

```typescript
let group = {
    molds: 'object',
    tools: 'object',
    lines: 'object',
    mergers: 'object',
    install: 'function'
}
```

### Install

**Install**是初始化行為，也是Core和Group交換資料的地方，於初次引用時執行，以AWS S3為例：

```typescript
// s3.js
const group = {
    install: (group, options, packhouse) => {
        const AWS = require('aws-sdk')
        group.service = new AWS.S3({
            apiVersion: options.apiVersion
        })
    }
}

module.exports = group
```

#### Add Group

我們可以藉由`addGroup`方法加入Group，並傳遞Options，但我們不推薦這麼做，請參閱正規化方法[Main](https://packhouse-doc.metalsheep.com/the-instance/main)。

```typescript
packhouse.addGroup('s3', () => {
    return {
        data: require('./s3'),
        options: {
            apiVersion: '2006-03-01'        
        }
    }
})
```

### Mergers

針對跨Group的設計的，當GroupA要使用GroupB的方法時不能直接使用對方，必須藉由merger與[Includ](https://packhouse-doc.metalsheep.com/the-instance/broken-reference)的引用才行，此目的能協助綁定上下文以便建立[追蹤](https://packhouse-doc.metalsheep.com/the-instance/event)行為。

```typescript
const group = {
    tools: {
        sum: {
            handler(self, v1, v2) {
                self.success(v1 + v2)
            }
        }
    }
}

const group2 = {
    mergers: {
        mySum: 'sum'
    },
    tools: {
        double: {
            install({ include }) {
                include('sum').tool('mySum/sum')
            },
            handler(self, value) {
                self.tool('sum')
                    .noGood(self.error)
                    .action(value, value, self.success)
            }
        }
    }
}

packhouse.addGroup('sum', () => {
    return {
        data: group
    }
})

packhouse.addGroup('double', () => {
    return {
        data: group2
    }
})

packhouse.tool('double/double').action(10, (error, result) => {
    console.log(result) // 20
})
```

## TypeScript

如果你使用TypeScript，可以使用我們提供的Declaration File：

```typescript
import { Group } from 'packhouse/types'

const group: Group = {}
```

## Lazy First

盡可能不要在外部宣告`require`，可以確保引入的效能、文件的生產與單元測試時Mock行為最佳化。

```typescript
// 這是個糟糕的例子 😢
const AWS = require('aws-sdk')
const group = {
    install: (group, options) => {
        group.service = new AWS.S3({
            apiVersion: options.apiVersion
        })
    }
}

module.exports = group
```

```typescript
// 這是個優良案例 🤣
const group = {
    install: (group, options) => {
        const AWS = require('aws-sdk')
        group.service = new AWS.S3({
            apiVersion: options.apiVersion
        })
    }
}

module.exports = group
```
