Formance from 0 to 0.5
Published: 2022-12-28 15:47:54

**What?**
Formance Stack เป็น open-source tool ที่ออกแบบมาเพื่อที่จะช่วย developer สร้าง, จัดการ, และติดตามการเข้าออกของเงินในบัญชี โดยเราสามารถนำ tool นี้มีใช้ได้ในโปรเจ็คขนาดเล็ก หรือแม้กระทั่งใน platform ทางการเงินขนาดใหญ่

**Formance Ledger?**
Formance Ledger คือ service ที่ทำให้เราสามารถติดตามการเคลื่อนไหวหรือ สถานะเกี่ยวกับการเงินได้แบบ real-time และเราสามารถ disign และบันทึก transaction ทางการเงินที่มีความสับซ้อนได้อีกด้วย ซึ่งเราสามารถเขียนโปรแกรมสั่งการได้โดยใช้ Numscript ที่ทำหน้าที่เป็น DSL (domain-specific language) ที่ถูกออกแบบมาช่วยเรา model transaction ทางการเงิน

**Hello Formance!!!**
มาลองใช้ง่ายแบบง่ายๆเพื่อให้เห็นภาพมากขึ้น Formance ได้จัดเตรียมวิธี install service ไว้หลายวิธีแต่วิธีที่ผมเลือกจะใช้ Docker

```zsh
docker run -p 3068:3068 \
-v $HOME/numary:/root/.numary \
--env NUMARY_SERVER_HTTP_BIND_ADDRESS="0.0.0.0:3068" \
ghcr.io/formancehq/ledger:latest
```
หรือ Docker compose ซึ่งจะมาพร้อมกับ service postgres ซึ่งเป็น database ที่ใช้แทน default ที่เป็น sqlite

```zsh
curl -L https://raw.githubusercontent.com/formancehq/ledger/main/docker-compose.yml -o docker-compose.yml

docker-compose up -d
```

ทดสอบโดยการใช้คำสั่ง

`curl -X GET http://127.0.0.1:3068/_info`

**Hello world!!!**
ในหัวนี้เราจะเรียนรู้:

- การสร้าง Formance Ledger
- สร้าง models transaction และ account โดยใช้ Numscript
- นำเงินเข้าสู่ระบบด้วย @world account
- ตรวจสอบ transaction และ ยอดคงเหลือใน account

อธิบาย @world account เพิ่มเติมที่ต้องมี account นี้เนื่องจากตัว Formance ledger มีการกำหนดว่าเงินที่เข้ามาในระบบไม่สามารถเสกมาจากอากาศลอยๆได้ ดังนั้นจึงต้องมี @world account เพื่อใช้นำเงินจากภายนอกเข้ามาสู่ในระบบ ledger ของเรา 

จากหัวข้อด้านบนตอนนี้เราจะมี service Ledger รันอยู่ในเครื่องแล้ว เราลองมาสร้าง transaction แรกกันด้วยการสร้าง **Numscript**

first.num
```javascript
send [COIN 100] (
  source = @world
  destination = @centralbank
)
```

```zsh
jq -Rs '{plain: .}' first.num \
| curl -H "Content-Type: application/json" \
-X POST --data-binary @- \
https://localhost/api/ledger/{default}/script
```
**Checking balances**
ตรวจสอบรายการสามารถทำได้ด้วยการส่งคำสั่ง

```zsh
curl --location --request GET 'http://localhost/api/ledger/{quickstart}/aggregate/balances?address=centralbank'
```

**Storage consideration**
ตัว Formance เองรองรับการเก็บข้อมูลไว้ใน storage 2 อย่างคือ Sqlite และ Postgres ซึ่งโดย default แล้วตัวระบบจะเลือกใช้ Sqlite มาให้ซึ่งสะดวกและง่ายสำหรับการทำการทดสอบบน local แต่ทางระบบเองก็มีการเตือนว่าไม่เหมาะสำหรับการนำมาใช้บน production product และกำลังจะถูก deprecated ใน Formance version 2.X
ตัวเลือกเดียวที่เหมาะสมก็จะเหลือแค่ Postgres ซึ่งเราสามารถใช้งานได้ด้วยการคำหนดค่า Environment

```zsh
NUMARY_STORAGE_DRIVER=postgres \
NUMARY_STORAGE_POSTGRES_CONN_STRING=postgresql://localhost/dbname \
```
**Concurrency Model**
Formance มีการออกแบบการควบคุม concurrency ของ transaction เพื่อป้องกันการเกิด race condition เป็น 2 ส่วนคือ

- Pre-commit in-memory or Redis-based locking
- Optimistic locking

ส่วนการเลือกระหว่าง in-memory or Redis นั่นพิจารณาจากว่าหากเรา deploy แบบ multi-instances ให้เลือกใช้ Redis
[อ่านเพิ่มเติม](https://docs.formance.com/ledger/reference/concurrency-model)

**Ledger separation**
การเลือกแบ่ง Ledger ใน Formance หรือพูดง่ายๆว่าการแบ่ง schema ของ postgres ว่าเราควรจะทำเป็น single ledger หรือ multi-ledger นั่นมีหลักการตัดสิน 2 ข้อคือ

- หาก application ของเราไม่มีความจำเป็นต้องแชร์ข้อมูลข้าม ledger กันสามารถทำ multi-ledger ได้
- application ที่มี workload ด้าน write สูงและสามารถเก็บข้อมูลแยกกันได้สามารถพิจารณาทำ multi-ledger ได้

[เพิ่มเติม](https://docs.formance.com/ledger/reference/ledgers)

**Account**
เป็นเสมือน container สำหรับ assets เราสามารถส่งและรับ assets ได้ผ่าน transaction โดยผลรวมของ account จะเท่ากับ

> balance(account)=∑postings(destination)−∑postings(source)

การตั้งชื่อ account มีการกำหนดว่าต้องตาม เงื่อนไขดังนี้
`^[a-zA-Z_0-9]+(:[a-zA-Z_0-9]+){0,}$`
และแนะนำให้ใช้เครื่องหมาย colon ให้การแบ่ง structure เช่น
`payments:001:authorizations:001
sales:001:contract`
นอกจากนั้นใน account เรายังสามารถเพิ่มตัว metadata เข้าไปได้ด้วยเพื่อใช้อธิบายรายละเอียดเพิ่มเติมของ account นั่นๆ
[เพิ่มเติม](https://docs.formance.com/ledger/reference/accounts)

**Posting**
คือการเคลื่อนที่ของจำนวนของ asset จาก account นึงไปยังอีก account นึง เช่น Alice ให้ 100 coins ไปที่ Bob

```json
{
  "source": "alice",
  "destination": "bob",
  "asset": "COIN",
  "amount": 100
}
```

**Transaction**
ใน Formance transaction คือการ model การรวมกันของ posting ซึ่งเจตนาคือต้องการต้องการทำให้เป็น atomically ตัวอย่างเช่น Alice ใช้ coin ซื้อ gem ผ่าน counter

```json
{
  "postings": [
    {
      "source": "alice",
      "destination": "teller",
      "amount": 100,
      "asset": "COIN"
    },
    {
      "source": "teller",
      "destination": "alice",
      "amount": 5,
      "asset": "GEM"
    }
  ]
}
```
[เพิ่มเติม](https://docs.formance.com/ledger/reference/transactions)

**Architecture**
[architecture](https://docs.formance.com/ledger/reference/architecture)
**Control dashborad**
[control dashborad](https://docs.formance.com/ledger/operations/using-the-control-dashboard)
`https://control.formance.com/`

**Mastering Numscript**
[coming soon](https://docs.formance.com/ledger/numscript/) 
[numscript template](https://docs.formance.com/ledger/numscript/templates/)