- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline - Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch - RTL: 351 Harbour-compatible functions - RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization - Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec) - HB_FUNC API: Full Harbour C API compatible Go bridge - Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT - Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST - Macro Compiler: Runtime AST parsing and evaluation - Debugger: TUI debugger with source display, breakpoints, stepping - FRB: Native + Pcode dual mode runtime binary - Tests: 13 packages ALL PASS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1281 lines
34 KiB
Markdown
1281 lines
34 KiB
Markdown
# Five: Harbour + Go 융합 전략
|
|
|
|
> 단순 포팅이 아닌, Harbour의 비즈니스 로직 표현력과
|
|
> Go의 현대적 생태계를 융합하여 새로운 개발 플랫폼으로 진화시키는 전략 문서
|
|
>
|
|
> Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
> All rights reserved.
|
|
|
|
---
|
|
|
|
## 목차
|
|
|
|
1. [현재 문제 진단](#1-현재-문제-진단)
|
|
2. [비전: 왜 Go인가](#2-비전-왜-go인가)
|
|
3. [설계 철학: 단순 포팅이 아닌 융합](#3-설계-철학-단순-포팅이-아닌-융합)
|
|
4. [Go 생태계 직접 연동](#4-go-생태계-직접-연동)
|
|
5. [동시성 모델 진화](#5-동시성-모델-진화)
|
|
6. [네트워크 네이티브](#6-네트워크-네이티브)
|
|
7. [멀티플랫폼 전략](#7-멀티플랫폼-전략)
|
|
8. [RDD 진화: DBF를 넘어서](#8-rdd-진화-dbf를-넘어서)
|
|
9. [언어 진화 제안](#9-언어-진화-제안)
|
|
10. [기존 코드 마이그레이션](#10-기존-코드-마이그레이션)
|
|
11. [생태계 구축 전략](#11-생태계-구축-전략)
|
|
12. [아키텍처 총괄](#12-아키텍처-총괄)
|
|
13. [로드맵](#13-로드맵)
|
|
|
|
---
|
|
|
|
## 1. 현재 문제 진단
|
|
|
|
### Harbour 생태계의 구조적 한계
|
|
|
|
```
|
|
문제 1: 생태계 정체
|
|
- 주요 기여자 수: ~5명 활동
|
|
- 최근 커밋 빈도: 월 1-2회
|
|
- 새로운 라이브러리/프레임워크: 거의 없음
|
|
- 패키지 매니저: 없음
|
|
- 결과: 개발자가 모든 것을 직접 구현해야 함
|
|
|
|
문제 2: 현대 기술 접근 불가
|
|
- HTTP/REST API: contrib에 기본적인 것만
|
|
- JSON/XML: 제한적
|
|
- WebSocket: 없음
|
|
- gRPC: 없음
|
|
- 클라우드 SDK: 없음
|
|
- 컨테이너/k8s: 고려되지 않은 설계
|
|
|
|
문제 3: 스레딩의 고질적 결함
|
|
- 글로벌 상태 + 수동 mutex → 레이스 컨디션
|
|
- GC suspend 모델 → 불안정
|
|
- 실무에서 MT 모드 회피 경향
|
|
|
|
문제 4: 배포/운영
|
|
- C 런타임 의존성
|
|
- 플랫폼별 빌드 설정 복잡
|
|
- 크로스 컴파일 어려움
|
|
- 컨테이너 이미지 대형화
|
|
|
|
문제 5: 개발 도구
|
|
- LSP/DAP: 없음
|
|
- 코드 포매터: 없음
|
|
- 린터: 없음
|
|
- IDE 지원: 구문 강조 수준
|
|
```
|
|
|
|
### Harbour의 핵심 강점 (보존 대상)
|
|
|
|
```
|
|
강점 1: xBase 명령어의 데이터 처리 표현력
|
|
USE customers
|
|
SET FILTER TO age > 30
|
|
INDEX ON lastname + firstname TO cust_name
|
|
SEEK "SMITH"
|
|
REPLACE salary WITH salary * 1.1
|
|
|
|
→ SQL보다 절차적이고, 일반 코드보다 선언적
|
|
→ 비즈니스 로직을 매우 간결하게 표현
|
|
|
|
강점 2: 매크로 시스템의 동적 유연성
|
|
cField := "salary"
|
|
REPLACE &cField WITH &cField * 1.1
|
|
→ 런타임 코드 생성, 동적 비즈니스 규칙 엔진에 강력
|
|
|
|
강점 3: 코드 블록의 함수형 표현
|
|
aData := { {1,"A"}, {2,"B"}, {3,"C"} }
|
|
ASort(aData, {|x,y| x[2] < y[2] })
|
|
AEval(aData, {|x| QOut(x[2]) })
|
|
|
|
강점 4: 검증된 대량 레거시 코드베이스
|
|
→ 수십 년 운영된 비즈니스 로직
|
|
→ 재작성 불가, 점진적 마이그레이션 필수
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 비전: 왜 Go인가
|
|
|
|
### Go가 Harbour의 약점을 정확히 보완
|
|
|
|
```
|
|
Harbour 약점 Go 강점 결합 효과
|
|
───────────── ────────── ─────────
|
|
생태계 정체 60,000+ 패키지 Go 패키지 직접 사용
|
|
스레딩 결함 goroutine + channel 구조적 동시성
|
|
네트워크 부재 net/http, gRPC 내장 HTTP/API 네이티브
|
|
배포 복잡 단일 바이너리 + 크로스컴파일 어디서든 실행
|
|
개발 도구 부재 gopls, delve 참조 가능 LSP/DAP 구현 용이
|
|
클라우드 미지원 K8s/Docker 네이티브 컨테이너 최적화
|
|
패키지 관리 없음 go modules 의존성 관리 해결
|
|
```
|
|
|
|
### Five가 Go에 더하는 가치
|
|
|
|
```
|
|
Go의 약점 Five가 보완 결합 효과
|
|
────────── ──────────── ──────────
|
|
class 문법 없음 CLASS/ENDCLASS 지원 OOP 직관적 표현
|
|
struct+interface 상속, 다형성, 연산자 오버로딩
|
|
메서드가 분산 정의 클래스 안에 응집
|
|
|
|
제네릭 제한적 동적 타이핑 유연성 타입에 구애받지 않는 코드
|
|
Go 1.18+이나 복잡 ANY 타입 자연스러움
|
|
|
|
enum 없음 xBase 표현력 비즈니스 로직 간결
|
|
iota 패턴 불편 SWITCH TYPE, 매크로
|
|
|
|
REPL 없음 harbour repl 빠른 프로토타이핑
|
|
컴파일 필수 대화형 탐색
|
|
|
|
DSL 표현력 부족 xBase 명령어 데이터 처리 선언적
|
|
USE/SEEK/REPLACE SQL보다 절차적이면서
|
|
같은 표현 불가 일반 코드보다 선언적
|
|
```
|
|
|
|
**핵심: Five는 Go에 class와 xBase DSL을 얹어주는 것이다.**
|
|
|
|
Go 개발자 관점에서 Five의 CLASS:
|
|
```harbour
|
|
// Five: 하나의 블록에 데이터 + 메서드가 응집
|
|
CLASS HttpClient
|
|
DATA cBaseUrl INIT ""
|
|
DATA nTimeout INIT 30
|
|
DATA oHeaders INIT {=>}
|
|
|
|
METHOD New(cUrl)
|
|
METHOD Get(cPath)
|
|
METHOD Post(cPath, hBody)
|
|
METHOD SetHeader(cKey, cVal)
|
|
ENDCLASS
|
|
|
|
METHOD New(cUrl) CLASS HttpClient
|
|
::cBaseUrl := cUrl
|
|
RETURN Self
|
|
|
|
METHOD Get(cPath) CLASS HttpClient
|
|
// net/http를 내부에서 사용
|
|
RETURN hbhttp.Get(::cBaseUrl + cPath, ::oHeaders)
|
|
|
|
METHOD SetHeader(cKey, cVal) CLASS HttpClient
|
|
::oHeaders[cKey] := cVal
|
|
RETURN Self
|
|
|
|
// 사용: 메서드 체이닝
|
|
LOCAL oApi := HttpClient():New("https://api.example.com")
|
|
oApi:SetHeader("Authorization", "Bearer " + cToken)
|
|
LOCAL hData := oApi:Get("/users")
|
|
```
|
|
|
|
```go
|
|
// 동일한 것을 순수 Go로 작성하면:
|
|
// 구조체 정의와 메서드가 분산됨
|
|
type HttpClient struct {
|
|
BaseUrl string
|
|
Timeout int
|
|
Headers map[string]string
|
|
}
|
|
|
|
func NewHttpClient(url string) *HttpClient { ... } // 별도 위치
|
|
func (c *HttpClient) Get(path string) { ... } // 별도 위치
|
|
func (c *HttpClient) Post(path string) { ... } // 별도 위치
|
|
func (c *HttpClient) SetHeader(k, v string) { ... } // 별도 위치
|
|
// → 클래스 개념이 파일 전체에 흩어짐
|
|
```
|
|
|
|
### 다른 언어가 아닌 이유
|
|
|
|
| 대안 | 기각 사유 |
|
|
|------|----------|
|
|
| Rust | 학습 곡선 극도로 높음, Harbour 사용자층과 부적합 |
|
|
| Java/Kotlin | JVM 의존, 단일 바이너리 불가, 시작 시간 |
|
|
| Python | 성능, GIL 문제, 타입 안전성 |
|
|
| C# (.NET) | MS 종속성, 리눅스 배포 복잡 |
|
|
| Node.js | 단일 스레드, 타입 안전성, 바이너리 배포 |
|
|
| **Go** | **단일 바이너리, goroutine, 거대 생태계, 학습 용이, 크로스컴파일** |
|
|
|
|
---
|
|
|
|
## 3. 설계 철학: 단순 포팅이 아닌 융합
|
|
|
|
### 기존 접근 (단순 포팅) — 이것을 하지 않는다
|
|
|
|
```
|
|
PRG → [Harbour 컴파일러 Go 포팅] → [Harbour VM Go 포팅] → 실행
|
|
↑ ↑
|
|
C 코드를 기계적으로 C 구조를 그대로
|
|
Go로 번역 Go로 재현
|
|
|
|
결과: Go로 작성된 Harbour일 뿐
|
|
Go 생태계 활용 불가
|
|
새로운 가치 없음
|
|
```
|
|
|
|
### 채택 접근 (융합) — Five
|
|
|
|
```
|
|
PRG → [Five 컴파일러] → Go 소스 코드 → go build → 네이티브 바이너리
|
|
↓
|
|
import "net/http" ← Go 표준 라이브러리
|
|
import "github.com/..." ← Go 생태계 전체
|
|
import "harbour-go/hbrt" ← Harbour 런타임
|
|
|
|
결과: Harbour 문법으로 작성하되
|
|
Go의 모든 것을 사용할 수 있는 새로운 언어
|
|
```
|
|
|
|
### 핵심 원칙
|
|
|
|
```
|
|
원칙 1: Harbour 문법 호환
|
|
기존 PRG 코드가 최소 수정으로 컴파일되어야 한다.
|
|
100% 호환이 아니라 95% 호환 + 마이그레이션 도구.
|
|
|
|
원칙 2: Go 생태계 1급 시민
|
|
Go 패키지를 PRG에서 직접 import하여 사용할 수 있어야 한다.
|
|
PRG 함수를 Go에서 직접 호출할 수 있어야 한다.
|
|
|
|
원칙 3: Go 철학 수용
|
|
"공유 메모리로 통신하지 말고, 통신으로 메모리를 공유하라"
|
|
에러는 값이다 (panic이 아닌 error 반환)
|
|
단순함을 추구한다
|
|
|
|
원칙 4: 전진적 진화
|
|
Clipper 호환 quirk는 선택적 호환 모드로 분리한다.
|
|
새 코드는 현대적 패턴을 권장한다.
|
|
기존 코드는 점진적으로 마이그레이션한다.
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Go 생태계 직접 연동
|
|
|
|
### 4.1 PRG에서 Go 패키지 사용
|
|
|
|
**현재 (불가능):**
|
|
```harbour
|
|
// Harbour에서 HTTP 서버? → 없음
|
|
// JSON 파싱? → 제한적
|
|
// PostgreSQL? → contrib/hbpgsql (불안정)
|
|
```
|
|
|
|
**Five에서 (직접 사용):**
|
|
```harbour
|
|
// Five 문법 확장: IMPORT
|
|
IMPORT "net/http"
|
|
IMPORT "encoding/json"
|
|
IMPORT "database/sql"
|
|
IMPORT _ "github.com/lib/pq" // PostgreSQL 드라이버
|
|
|
|
FUNCTION StartServer(cPort)
|
|
LOCAL oMux := http.NewServeMux()
|
|
|
|
oMux:HandleFunc("/api/customers", {|w, r|
|
|
LOCAL aData := GetCustomers()
|
|
LOCAL cJson := json.Marshal(aData)
|
|
w:Write(cJson)
|
|
})
|
|
|
|
? "Server starting on port " + cPort
|
|
http.ListenAndServe(":" + cPort, oMux)
|
|
RETURN NIL
|
|
```
|
|
|
|
**생성되는 Go 코드:**
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"encoding/json"
|
|
"database/sql"
|
|
_ "github.com/lib/pq"
|
|
"harbour-go/hbrt"
|
|
)
|
|
|
|
func HB_STARTSERVER(t *hbrt.Thread) {
|
|
t.Frame(1, 2)
|
|
defer t.EndProc()
|
|
|
|
mux := http.NewServeMux()
|
|
t.PushGoValue(mux)
|
|
t.PopLocal(2) // oMux
|
|
|
|
// HandleFunc with Harbour code block
|
|
mux.HandleFunc("/api/customers", func(w http.ResponseWriter, r *http.Request) {
|
|
bt := t.VM().NewThread()
|
|
defer bt.Destroy()
|
|
// ... Harbour 코드 블록 실행 ...
|
|
data := bt.CallHarbour("GETCUSTOMERS")
|
|
jsonBytes, _ := json.Marshal(hbrt.ToGoValue(data))
|
|
w.Write(jsonBytes)
|
|
})
|
|
|
|
http.ListenAndServe(":" + t.LocalAsString(1), mux)
|
|
}
|
|
```
|
|
|
|
### 4.2 Go에서 Five/Harbour 호출
|
|
|
|
```go
|
|
// Go 프로젝트에서 Five를 라이브러리로 사용
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"harbour-go/hbrt"
|
|
_ "myapp/harbour_modules" // PRG에서 생성된 Go 코드
|
|
)
|
|
|
|
func main() {
|
|
vm := hbrt.NewVM()
|
|
|
|
// Harbour 함수 호출
|
|
result := vm.Call("CalcTax", 50000.0, "KR")
|
|
fmt.Printf("Tax: %.2f\n", result.AsDouble())
|
|
|
|
// Harbour의 RDD를 Go에서 사용
|
|
vm.Exec(`
|
|
USE customers VIA DBFCDX
|
|
SET FILTER TO country = "KR"
|
|
GO TOP
|
|
`)
|
|
|
|
// 결과를 Go 구조체로 변환
|
|
for !vm.Call("EOF").AsBool() {
|
|
name := vm.Call("FIELD->NAME").AsString()
|
|
fmt.Println(name)
|
|
vm.Exec("SKIP")
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4.3 타입 브릿지
|
|
|
|
```
|
|
Five Value ←→ Go 타입 자동 변환
|
|
|
|
Five Go
|
|
─────── ──────
|
|
NIL nil (interface{})
|
|
LOGICAL (.T./.F.) bool
|
|
INTEGER/LONG int64
|
|
DOUBLE float64
|
|
STRING string
|
|
DATE time.Time
|
|
TIMESTAMP time.Time
|
|
ARRAY []interface{} 또는 []hbrt.Value
|
|
HASH map[string]interface{} 또는 map[hbrt.Value]hbrt.Value
|
|
OBJECT *hbrt.Object (Go interface 구현 가능)
|
|
BLOCK func(...hbrt.Value) hbrt.Value
|
|
```
|
|
|
|
```go
|
|
// 타입 브릿지 API
|
|
hbrt.ToGoValue(v Value) interface{} // Five → Go
|
|
hbrt.FromGoValue(v interface{}) Value // Go → Five
|
|
|
|
// 구조체 매핑
|
|
type Customer struct {
|
|
Name string `hb:"cName"`
|
|
Age int `hb:"nAge"`
|
|
Active bool `hb:"lActive"`
|
|
}
|
|
|
|
// Five 객체 → Go 구조체
|
|
var cust Customer
|
|
hbrt.Unmarshal(hbObject, &cust)
|
|
|
|
// Go 구조체 → Five 해시
|
|
hbHash := hbrt.Marshal(cust)
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 동시성 모델 진화
|
|
|
|
### 5.1 현재: Harbour의 깨진 스레딩
|
|
|
|
```harbour
|
|
// 현재 Harbour: 불안정, 실무에서 회피
|
|
hb_threadStart(@Worker())
|
|
|
|
STATIC FUNCTION Worker()
|
|
// 글로벌 상태 접근 → 레이스 컨디션
|
|
// GC 타이밍 → 크래시
|
|
// 에러 처리 → 불완전
|
|
RETURN NIL
|
|
```
|
|
|
|
### 5.2 Five: goroutine 네이티브 통합
|
|
|
|
**새 키워드: `GO` (goroutine 시작)**
|
|
|
|
```harbour
|
|
FUNCTION ProcessOrders(aOrders)
|
|
LOCAL ch := CHANNEL(10) // 버퍼 채널
|
|
|
|
// goroutine으로 병렬 처리
|
|
FOR EACH oOrder IN aOrders
|
|
GO ProcessOne(oOrder, ch)
|
|
NEXT
|
|
|
|
// 결과 수집
|
|
LOCAL aResults := {}
|
|
FOR i := 1 TO Len(aOrders)
|
|
AAdd(aResults, RECEIVE(ch))
|
|
NEXT
|
|
|
|
RETURN aResults
|
|
|
|
FUNCTION ProcessOne(oOrder, ch)
|
|
LOCAL nTotal := CalcTotal(oOrder)
|
|
SEND(ch, {oOrder:id, nTotal})
|
|
RETURN NIL
|
|
```
|
|
|
|
**생성되는 Go 코드:**
|
|
```go
|
|
func HB_PROCESSORDERS(t *hbrt.Thread) {
|
|
t.Frame(1, 2)
|
|
defer t.EndProc()
|
|
|
|
ch := make(chan hbrt.Value, 10)
|
|
t.PushGoValue(ch)
|
|
t.PopLocal(2)
|
|
|
|
orders := t.Local(1).AsArray()
|
|
for _, order := range orders.Items() {
|
|
order := order // capture
|
|
go func() {
|
|
gt := t.VM().NewThread()
|
|
defer gt.Destroy()
|
|
gt.PushSymbol(sym_PROCESSONE)
|
|
gt.PushNil()
|
|
gt.PushValue(order)
|
|
gt.PushGoValue(ch)
|
|
gt.Function(2)
|
|
}()
|
|
}
|
|
|
|
results := hbrt.NewArray(0)
|
|
for i := 0; i < orders.Len(); i++ {
|
|
val := <-ch
|
|
results.Add(val)
|
|
}
|
|
t.PushValue(hbrt.MakeArrayFrom(results))
|
|
t.RetValue()
|
|
}
|
|
```
|
|
|
|
### 5.3 동시성 프리미티브
|
|
|
|
```harbour
|
|
// 채널 (Go channel)
|
|
LOCAL ch := CHANNEL(0) // unbuffered
|
|
LOCAL ch := CHANNEL(100) // buffered
|
|
|
|
SEND(ch, value) // ch <- value
|
|
LOCAL val := RECEIVE(ch) // val := <-ch
|
|
|
|
// SELECT (Go select)
|
|
SELECT CHANNEL
|
|
CASE val := RECEIVE(ch1)
|
|
? "From ch1:", val
|
|
CASE val := RECEIVE(ch2)
|
|
? "From ch2:", val
|
|
CASE AFTER(5000) // 5초 타임아웃
|
|
? "Timeout"
|
|
END SELECT
|
|
|
|
// WaitGroup
|
|
LOCAL wg := WAITGROUP()
|
|
FOR i := 1 TO 10
|
|
wg:Add(1)
|
|
GO func(wg, i)
|
|
NEXT
|
|
wg:Wait()
|
|
|
|
// Mutex (필요한 경우만)
|
|
LOCAL mtx := MUTEX()
|
|
mtx:Lock()
|
|
// critical section
|
|
mtx:Unlock()
|
|
```
|
|
|
|
### 5.4 안전한 공유: 구조적 보장
|
|
|
|
```harbour
|
|
// Five는 구조적으로 레이스를 방지한다:
|
|
|
|
// 규칙 1: LOCAL 변수는 goroutine-local → 공유 불가능
|
|
// 규칙 2: 데이터 공유는 CHANNEL로만
|
|
// 규칙 3: PUBLIC 변수는 atomic read/write
|
|
// 규칙 4: STATIC 변수 접근은 자동 sync
|
|
|
|
// 컴파일러가 감지하고 경고:
|
|
STATIC nCount := 0
|
|
GO {||
|
|
nCount++ // WARNING: STATIC access in goroutine.
|
|
// Use CHANNEL or ATOMIC() instead.
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. 네트워크 네이티브
|
|
|
|
### 6.1 HTTP 서버 (내장)
|
|
|
|
```harbour
|
|
IMPORT "harbour-go/hbweb"
|
|
|
|
FUNCTION Main()
|
|
LOCAL oApp := hbweb.New()
|
|
|
|
// REST API 라우팅
|
|
oApp:GET("/api/customers", @ListCustomers())
|
|
oApp:GET("/api/customers/:id", @GetCustomer())
|
|
oApp:POST("/api/customers", @CreateCustomer())
|
|
oApp:PUT("/api/customers/:id", @UpdateCustomer())
|
|
oApp:DELETE("/api/customers/:id", @DeleteCustomer())
|
|
|
|
// 미들웨어
|
|
oApp:Use(@LogMiddleware())
|
|
oApp:Use(@AuthMiddleware())
|
|
|
|
oApp:Listen(":8080")
|
|
RETURN NIL
|
|
|
|
FUNCTION ListCustomers(ctx)
|
|
USE customers VIA DBFCDX
|
|
LOCAL aResult := {}
|
|
|
|
GO TOP
|
|
DO WHILE !EOF()
|
|
AAdd(aResult, {;
|
|
"id" => RecNo(), ;
|
|
"name" => FIELD->name, ;
|
|
"city" => FIELD->city ;
|
|
})
|
|
SKIP
|
|
ENDDO
|
|
USE
|
|
|
|
ctx:JSON(200, aResult)
|
|
RETURN NIL
|
|
```
|
|
|
|
### 6.2 HTTP 클라이언트
|
|
|
|
```harbour
|
|
IMPORT "harbour-go/hbhttp"
|
|
|
|
FUNCTION CallExternalAPI()
|
|
LOCAL oResp := hbhttp.Get("https://api.example.com/data", {;
|
|
"Authorization" => "Bearer " + cToken, ;
|
|
"Accept" => "application/json" ;
|
|
})
|
|
|
|
IF oResp:StatusCode == 200
|
|
LOCAL hData := hbhttp.ParseJSON(oResp:Body)
|
|
? hData["result"]
|
|
ELSE
|
|
? "Error:", oResp:StatusCode
|
|
ENDIF
|
|
|
|
RETURN NIL
|
|
```
|
|
|
|
### 6.3 WebSocket
|
|
|
|
```harbour
|
|
IMPORT "harbour-go/hbws"
|
|
|
|
FUNCTION ChatServer()
|
|
LOCAL oWS := hbws.NewServer()
|
|
|
|
oWS:OnConnect({|conn|
|
|
? "Client connected:", conn:ID
|
|
})
|
|
|
|
oWS:OnMessage({|conn, cMsg|
|
|
// 모든 클라이언트에 브로드캐스트
|
|
oWS:Broadcast(cMsg)
|
|
})
|
|
|
|
oWS:Listen(":9090")
|
|
RETURN NIL
|
|
```
|
|
|
|
### 6.4 gRPC
|
|
|
|
```harbour
|
|
IMPORT "harbour-go/hbgrpc"
|
|
|
|
// .proto 파일에서 자동 생성된 Five 바인딩 사용
|
|
FUNCTION RunGRPCServer()
|
|
LOCAL oServer := hbgrpc.NewServer()
|
|
|
|
oServer:RegisterService("CustomerService", {;
|
|
"GetCustomer" => @GrpcGetCustomer(), ;
|
|
"ListCustomers" => @GrpcListCustomers() ;
|
|
})
|
|
|
|
oServer:Listen(":50051")
|
|
RETURN NIL
|
|
```
|
|
|
|
---
|
|
|
|
## 7. 멀티플랫폼 전략
|
|
|
|
### 7.1 Go의 크로스 컴파일 활용
|
|
|
|
```bash
|
|
# 단일 명령으로 모든 플랫폼 바이너리 생성
|
|
harbour build --target linux/amd64 myapp.prg -o myapp-linux
|
|
harbour build --target windows/amd64 myapp.prg -o myapp.exe
|
|
harbour build --target darwin/arm64 myapp.prg -o myapp-mac
|
|
harbour build --target linux/arm64 myapp.prg -o myapp-arm
|
|
|
|
# 내부적으로:
|
|
# GOOS=linux GOARCH=amd64 go build -o myapp-linux
|
|
```
|
|
|
|
### 7.2 Docker/컨테이너 최적화
|
|
|
|
```dockerfile
|
|
# 최소 컨테이너 이미지
|
|
FROM scratch
|
|
COPY myapp /myapp
|
|
COPY data/ /data/
|
|
ENTRYPOINT ["/myapp"]
|
|
|
|
# 이미지 크기: ~10-15MB (Go 정적 바이너리)
|
|
# 기존 Harbour + C 런타임: 100MB+
|
|
```
|
|
|
|
```harbour
|
|
// 컨테이너 친화적 설계
|
|
FUNCTION Main()
|
|
// 환경 변수에서 설정 읽기 (12-Factor App)
|
|
LOCAL cPort := GetEnv("PORT", "8080")
|
|
LOCAL cDBPath := GetEnv("DB_PATH", "/data")
|
|
|
|
// 헬스체크 엔드포인트
|
|
oApp:GET("/health", {|ctx| ctx:JSON(200, {"status" => "ok"}) })
|
|
|
|
// Graceful shutdown
|
|
ON SIGNAL SIGTERM DO Shutdown()
|
|
|
|
oApp:Listen(":" + cPort)
|
|
RETURN NIL
|
|
```
|
|
|
|
### 7.3 임베디드/IoT
|
|
|
|
```
|
|
Go의 타겟:
|
|
linux/arm → Raspberry Pi
|
|
linux/arm64 → ARM 서버
|
|
linux/mips → 라우터/IoT
|
|
|
|
Five 활용:
|
|
→ xBase 데이터 처리를 IoT 디바이스에서 직접 실행
|
|
→ 엣지 컴퓨팅: 현장에서 데이터 수집 + 필터링
|
|
→ 저사양 디바이스: Go의 낮은 메모리 사용량
|
|
```
|
|
|
|
---
|
|
|
|
## 8. RDD 진화: DBF를 넘어서
|
|
|
|
### 8.1 현재 RDD 체계 보존
|
|
|
|
```harbour
|
|
// 기존 DBF 코드: 100% 호환
|
|
USE customers VIA DBFCDX
|
|
SET INDEX TO cust_name
|
|
SEEK "SMITH"
|
|
? FIELD->name, FIELD->salary
|
|
USE
|
|
```
|
|
|
|
### 8.2 새로운 RDD 드라이버: SQL 데이터베이스
|
|
|
|
```harbour
|
|
// PostgreSQL을 RDD로 사용
|
|
USE "customers" VIA PGSQL CONNECTION "postgres://localhost/mydb"
|
|
|
|
// 동일한 xBase 명령어로 조작!
|
|
GO TOP
|
|
SET FILTER TO salary > 50000
|
|
DO WHILE !EOF()
|
|
? FIELD->name, FIELD->salary
|
|
REPLACE salary WITH salary * 1.1
|
|
SKIP
|
|
ENDDO
|
|
USE
|
|
|
|
// 내부적으로:
|
|
// GO TOP → SELECT * FROM customers
|
|
// SET FILTER → WHERE salary > 50000
|
|
// FIELD->name → row["name"]
|
|
// REPLACE → UPDATE customers SET salary = ... WHERE id = ...
|
|
// SKIP → cursor.Next()
|
|
```
|
|
|
|
### 8.3 RDD 드라이버 맵
|
|
|
|
```
|
|
기존 (보존):
|
|
DBFNTX → DBF + NTX 인덱스
|
|
DBFCDX → DBF + CDX 인덱스
|
|
DBFFPT → DBF + 메모 필드
|
|
|
|
새로 추가:
|
|
PGSQL → PostgreSQL (database/sql + lib/pq)
|
|
MYSQL → MySQL (database/sql + go-sql-driver/mysql)
|
|
SQLITE → SQLite (database/sql + mattn/go-sqlite3)
|
|
MONGODB → MongoDB (go.mongodb.org/mongo-driver)
|
|
REST → REST API 엔드포인트를 테이블처럼 사용
|
|
CSV → CSV 파일
|
|
JSON → JSON 파일/API
|
|
PARQUET → Apache Parquet (분석용)
|
|
```
|
|
|
|
### 8.4 RDD 간 투명한 데이터 이동
|
|
|
|
```harbour
|
|
// DBF에서 PostgreSQL로 마이그레이션
|
|
USE customers VIA DBFCDX
|
|
USE pg_customers VIA PGSQL CONNECTION cPgConn ALIAS pgcust
|
|
|
|
SELECT customers
|
|
GO TOP
|
|
DO WHILE !EOF()
|
|
SELECT pgcust
|
|
APPEND BLANK
|
|
REPLACE name WITH customers->name
|
|
REPLACE salary WITH customers->salary
|
|
REPLACE country WITH customers->country
|
|
SELECT customers
|
|
SKIP
|
|
ENDDO
|
|
```
|
|
|
|
### 8.5 쿼리 언어 확장
|
|
|
|
```harbour
|
|
// 기존 xBase 방식 (보존)
|
|
USE customers
|
|
SET FILTER TO country = "KR" .AND. salary > 50000
|
|
INDEX ON lastname TO temp_idx
|
|
GO TOP
|
|
|
|
// 새로운 방식: 인라인 쿼리
|
|
LOCAL aResult := QUERY FROM customers ;
|
|
WHERE country = "KR" .AND. salary > 50000 ;
|
|
ORDER BY lastname ;
|
|
INTO ARRAY
|
|
|
|
// SQL 직접 실행 (SQL RDD 사용 시)
|
|
LOCAL aRows := SQL("SELECT name, salary FROM customers WHERE country = $1", "KR")
|
|
```
|
|
|
|
---
|
|
|
|
## 9. 언어 진화 제안
|
|
|
|
### 9.1 에러 처리 현대화
|
|
|
|
**현재: BEGIN SEQUENCE (goto 기반)**
|
|
```harbour
|
|
BEGIN SEQUENCE
|
|
USE customers
|
|
// ...
|
|
RECOVER USING oErr
|
|
? "Error:", oErr:description
|
|
END SEQUENCE
|
|
```
|
|
|
|
**추가: TRY-CATCH (Go error 스타일 옵션)**
|
|
```harbour
|
|
// 방식 A: 기존 방식 (호환)
|
|
BEGIN SEQUENCE
|
|
result := RiskyOperation()
|
|
RECOVER USING oErr
|
|
LogError(oErr)
|
|
END SEQUENCE
|
|
|
|
// 방식 B: 새 방식 (Go 스타일, 선택적)
|
|
result, err := RiskyOperation()
|
|
IF err != NIL
|
|
LogError(err)
|
|
RETURN NIL
|
|
ENDIF
|
|
```
|
|
|
|
### 9.2 타입 힌트 (선택적)
|
|
|
|
```harbour
|
|
// 기존: 타입 없음 (호환)
|
|
FUNCTION Add(a, b)
|
|
RETURN a + b
|
|
|
|
// 새로운: 타입 힌트 (선택적, 컴파일러 최적화에 활용)
|
|
FUNCTION Add(a AS NUMERIC, b AS NUMERIC) AS NUMERIC
|
|
RETURN a + b
|
|
|
|
// 구조체 타입 (Go struct와 브릿지)
|
|
TYPE Customer
|
|
DATA cName AS STRING
|
|
DATA nAge AS INTEGER
|
|
DATA lActive AS LOGICAL := .T.
|
|
END TYPE
|
|
|
|
// 컴파일러가 타입 힌트를 활용하여:
|
|
// 1. 더 효율적인 Go 코드 생성
|
|
// 2. 컴파일 타임 타입 체크
|
|
// 3. Go 구조체와 직접 매핑
|
|
```
|
|
|
|
### 9.3 람다 / 화살표 함수
|
|
|
|
```harbour
|
|
// 기존: 코드 블록 (호환)
|
|
ASort(arr, {|a,b| a < b})
|
|
AEval(arr, {|x| QOut(x)})
|
|
|
|
// 새로운: 화살표 함수 (여러 줄 가능)
|
|
ASort(arr, (a, b) => a < b)
|
|
|
|
transformed := AMap(arr, (x) => {
|
|
LOCAL result := ProcessItem(x)
|
|
RETURN result * 2
|
|
})
|
|
```
|
|
|
|
### 9.4 패턴 매칭 (새 기능)
|
|
|
|
```harbour
|
|
// 타입 기반 분기
|
|
SWITCH TYPE OF value
|
|
CASE NUMERIC
|
|
? "Number:", value
|
|
CASE STRING
|
|
? "Text:", value
|
|
CASE ARRAY
|
|
? "Array with", Len(value), "items"
|
|
CASE OBJECT
|
|
? "Object of class:", value:ClassName()
|
|
OTHERWISE
|
|
? "Unknown type"
|
|
END SWITCH
|
|
```
|
|
|
|
### 9.5 구조적 분해 (새 기능)
|
|
|
|
```harbour
|
|
// 배열 분해
|
|
LOCAL {a, b, c} := {1, 2, 3}
|
|
|
|
// 해시 분해
|
|
LOCAL {name, age} := {"name" => "Kim", "age" => 30}
|
|
|
|
// 함수 다중 반환 (Go 스타일)
|
|
FUNCTION Divide(a, b)
|
|
IF b == 0
|
|
RETURN 0, .T. // result, error
|
|
ENDIF
|
|
RETURN a / b, .F.
|
|
|
|
LOCAL result, lError := Divide(10, 3)
|
|
```
|
|
|
|
### 9.6 호환성 모드 플래그
|
|
|
|
```harbour
|
|
// 파일 또는 프로젝트 레벨에서 호환 모드 지정
|
|
#pragma compatibility(clipper) // Clipper 호환 quirks 활성화
|
|
#pragma compatibility(harbour) // Harbour 호환
|
|
#pragma compatibility(five) // Five 모던 모드 (기본값)
|
|
|
|
// clipper 모드:
|
|
// - STRING - STRING: 패딩 동작
|
|
// - DATE + DATE: 줄리안 합산
|
|
// - SET EXACT OFF 기본
|
|
// - 63자 심볼 이름 제한
|
|
|
|
// five 모드:
|
|
// - STRING - STRING: 에러 (의미 없는 연산)
|
|
// - DATE + DATE: 에러
|
|
// - SET EXACT ON 기본
|
|
// - 심볼 이름 제한 없음
|
|
// - 타입 힌트 활성화
|
|
// - 다중 반환 활성화
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 기존 코드 마이그레이션
|
|
|
|
### 10.1 마이그레이션 도구
|
|
|
|
```bash
|
|
# 기존 PRG 코드 분석
|
|
harbour migrate analyze ./src/*.prg
|
|
|
|
# 출력:
|
|
# ─────────────────────────────────────
|
|
# 파일 분석 완료: 150개 PRG 파일
|
|
#
|
|
# 호환성:
|
|
# 즉시 컴파일 가능: 120 (80%)
|
|
# 자동 수정 가능: 25 (17%)
|
|
# 수동 수정 필요: 5 (3%)
|
|
#
|
|
# 자동 수정 항목:
|
|
# IIF → iif (대소문자) : 45건
|
|
# SET PRINTER → 제거 (콘솔 출력 변경) : 12건
|
|
# ANNOUNCE → 불필요 (Go 모듈로 대체) : 8건
|
|
#
|
|
# 수동 수정 항목:
|
|
# 인라인 C 코드 (#pragma BEGINDUMP) : 3건
|
|
# OS별 API 호출 (WinAPI) : 2건
|
|
# ─────────────────────────────────────
|
|
|
|
# 자동 수정 적용
|
|
harbour migrate fix ./src/*.prg --output ./src_five/
|
|
```
|
|
|
|
### 10.2 점진적 마이그레이션 패턴
|
|
|
|
```
|
|
Phase A: 기존 PRG을 Five로 컴파일 (최소 변경)
|
|
→ 95% 코드가 그대로 동작
|
|
→ 나머지 5%는 마이그레이션 도구가 변환
|
|
|
|
Phase B: 새로운 기능은 Five 확장 문법으로 작성
|
|
→ Go 패키지 import
|
|
→ goroutine 사용
|
|
→ HTTP API 추가
|
|
|
|
Phase C: 기존 코드를 점진적으로 현대화
|
|
→ 타입 힌트 추가
|
|
→ 에러 처리 현대화
|
|
→ SQL RDD로 DB 마이그레이션
|
|
```
|
|
|
|
### 10.3 C 코드 (#pragma BEGINDUMP) 처리
|
|
|
|
```harbour
|
|
// 기존: C 인라인 코드
|
|
#pragma BEGINDUMP
|
|
#include <hbapi.h>
|
|
HB_FUNC( MYEXTFUNC )
|
|
{
|
|
hb_retni( some_c_library_call() );
|
|
}
|
|
#pragma ENDDUMP
|
|
```
|
|
|
|
**마이그레이션 옵션:**
|
|
|
|
```
|
|
옵션 A: CGo로 변환
|
|
→ C 코드를 CGo wrapper로 감쌈
|
|
→ 기존 C 라이브러리 계속 사용 가능
|
|
→ 성능 오버헤드 있음 (CGo 호출 비용)
|
|
|
|
옵션 B: Go 네이티브로 재작성
|
|
→ C 라이브러리의 Go 대안 사용
|
|
→ 가장 깔끔하지만 작업량 큼
|
|
|
|
옵션 C: Five 플러그인 시스템
|
|
→ Go plugin 또는 Wasm으로 확장
|
|
→ 독립적인 빌드/배포
|
|
```
|
|
|
|
---
|
|
|
|
## 11. 생태계 구축 전략
|
|
|
|
### 11.1 패키지 매니저
|
|
|
|
```bash
|
|
# Go modules 기반
|
|
harbour mod init myapp
|
|
harbour mod tidy
|
|
|
|
# go.mod 파일이 의존성 관리
|
|
# harbour.mod 파일이 Five 특화 설정 관리
|
|
```
|
|
|
|
```
|
|
harbour.mod:
|
|
module myapp
|
|
five 1.0
|
|
compatibility harbour
|
|
|
|
require (
|
|
harbour-go/hbrt v1.0.0
|
|
harbour-go/hbrtl v1.0.0
|
|
harbour-go/hbrdd v1.0.0
|
|
harbour-go/hbweb v1.0.0
|
|
)
|
|
|
|
go.mod:
|
|
module myapp
|
|
go 1.23
|
|
|
|
require (
|
|
harbour-go/hbrt v1.0.0
|
|
github.com/lib/pq v1.10.0
|
|
// ... Go 의존성
|
|
)
|
|
```
|
|
|
|
### 11.2 표준 라이브러리 확장
|
|
|
|
```
|
|
harbour-go/hbrt ← 핵심 런타임 (Value, Thread, Symbol, Class)
|
|
harbour-go/hbrtl ← 기존 RTL 호환 함수 (STR, VAL, SUBSTR, ...)
|
|
harbour-go/hbrdd ← RDD 프레임워크 + DBF/NTX/CDX 드라이버
|
|
harbour-go/hbweb ← HTTP 서버/클라이언트 프레임워크
|
|
harbour-go/hbsql ← SQL RDD 드라이버 (PG, MySQL, SQLite)
|
|
harbour-go/hbjson ← JSON/XML/YAML 처리
|
|
harbour-go/hbcli ← CLI 프레임워크 (cobra 기반)
|
|
harbour-go/hbtest ← 테스트 프레임워크
|
|
harbour-go/hblog ← 구조적 로깅 (slog 기반)
|
|
harbour-go/hbcrypto ← 암호화/해싱
|
|
harbour-go/hbmail ← 이메일 발송
|
|
```
|
|
|
|
### 11.3 개발 도구
|
|
|
|
```
|
|
harbour lsp ← Language Server Protocol (에디터 통합)
|
|
harbour dap ← Debug Adapter Protocol (디버거)
|
|
harbour fmt ← 코드 포매터
|
|
harbour lint ← 린터 (코드 품질 검사)
|
|
harbour test ← 테스트 러너
|
|
harbour doc ← 문서 생성기
|
|
harbour repl ← 대화형 셸
|
|
harbour migrate ← 마이그레이션 도구
|
|
```
|
|
|
|
### 11.4 VSCode 확장
|
|
|
|
```
|
|
five-vscode/
|
|
├── syntaxes/ ← TextMate 문법 (구문 강조)
|
|
├── language-configuration.json
|
|
├── snippets/ ← 코드 스니펫
|
|
└── extension.js ← LSP 클라이언트 연결
|
|
```
|
|
|
|
---
|
|
|
|
## 12. 아키텍처 총괄
|
|
|
|
### 전체 시스템 구조
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ Five CLI │
|
|
│ harbour build | run | fmt | lint | test | lsp | migrate │
|
|
└──────────┬───────────────────────────────────┬───────────┘
|
|
│ │
|
|
┌──────▼──────┐ ┌───────▼───────┐
|
|
│ Compiler │ │ Dev Tools │
|
|
│ ┌────────┐ │ │ LSP, DAP, │
|
|
│ │ Lexer │ │ │ Formatter │
|
|
│ ├────────┤ │ └───────────────┘
|
|
│ │ Parser │ │
|
|
│ ├────────┤ │
|
|
│ │Analyzer│ │
|
|
│ ├────────┤ │
|
|
│ │ GenGo │ │ ← PRG → Go 소스 생성
|
|
│ └────────┘ │
|
|
└──────┬───────┘
|
|
│ 생성된 .go 파일
|
|
▼
|
|
┌──────────────────────────────────────────────────────┐
|
|
│ Go Build System │
|
|
│ go build (표준 Go 컴파일러) │
|
|
│ │
|
|
│ 의존성: │
|
|
│ ┌────────────────────────────────────────────────┐ │
|
|
│ │ harbour-go/hbrt ← 핵심 런타임 │ │
|
|
│ │ harbour-go/hbrtl ← 표준 함수 라이브러리 │ │
|
|
│ │ harbour-go/hbrdd ← 데이터베이스 드라이버 │ │
|
|
│ │ harbour-go/hbweb ← 웹 프레임워크 │ │
|
|
│ │ harbour-go/hbsql ← SQL 드라이버 │ │
|
|
│ ├────────────────────────────────────────────────┤ │
|
|
│ │ net/http ← Go 표준 라이브러리 │ │
|
|
│ │ database/sql ← Go 표준 라이브러리 │ │
|
|
│ │ encoding/json ← Go 표준 라이브러리 │ │
|
|
│ │ github.com/... ← Go 생태계 전체 │ │
|
|
│ └────────────────────────────────────────────────┘ │
|
|
└──────────────────────────┬────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────┐
|
|
│ 단일 네이티브 바이너리 │
|
|
│ (정적 링크, ~10MB) │
|
|
│ 모든 OS/아키텍처 │
|
|
└─────────────────────┘
|
|
```
|
|
|
|
### 핵심 런타임 내부 구조
|
|
|
|
```
|
|
hbrt (harbour-go runtime)
|
|
├── Value ← Tagged Value 16B (harbour-type-system-analysis.md 참조)
|
|
├── Thread ← goroutine별 실행 컨텍스트
|
|
│ ├── stack ← eval 스택 (goroutine-local, 락 불필요)
|
|
│ ├── locals ← 로컬 변수 (goroutine-local)
|
|
│ ├── memvars ← PRIVATE (goroutine-local map)
|
|
│ └── callStack ← 호출 스택 (goroutine-local)
|
|
├── VM ← 공유 상태
|
|
│ ├── symbols ← 심볼 테이블 (sync.RWMutex)
|
|
│ ├── classes ← 클래스 레지스트리 (sync.RWMutex)
|
|
│ ├── publics ← PUBLIC 변수 (sync.RWMutex)
|
|
│ └── modules ← 로드된 모듈 목록
|
|
├── ops ← 연산 (Plus, Minus, Equal, ...)
|
|
├── Bridge ← Go ↔ Five 타입 변환
|
|
└── Macro ← 런타임 매크로 컴파일러
|
|
```
|
|
|
|
---
|
|
|
|
## 13. 로드맵
|
|
|
|
### Phase 1: 기반 (Month 1-2)
|
|
|
|
```
|
|
목표: "Hello World"가 PRG → Go → 실행되는 것
|
|
|
|
구현:
|
|
[x] 프로젝트 구조 설정 (Go 모듈)
|
|
[ ] hbrt/value.go — Tagged Value 16B
|
|
[ ] hbrt/thread.go — 스택, 로컬 변수
|
|
[ ] hbrt/ops_arith.go — 산술 연산
|
|
[ ] hbrt/ops_compare.go — 비교 연산
|
|
[ ] hbrtl/console.go — QOut, QQOut
|
|
[ ] hbrtl/strings.go — 기본 문자열 함수
|
|
[ ] compiler/lexer.go — PRG 렉서
|
|
[ ] compiler/parser.go — 기본 구문 파서
|
|
[ ] compiler/gengo.go — Go 코드 생성
|
|
|
|
검증:
|
|
FUNCTION Main()
|
|
? "Hello World"
|
|
? 1 + 2
|
|
? "Result: " + Str(10 * 3)
|
|
RETURN NIL
|
|
```
|
|
|
|
### Phase 2: 제어 흐름 + 함수 (Month 3)
|
|
|
|
```
|
|
목표: IF, DO WHILE, FOR, 함수 호출이 동작
|
|
|
|
추가 구현:
|
|
[ ] 제어 흐름 (IF/ELSEIF/ELSE, DO WHILE, FOR, FOR EACH)
|
|
[ ] 함수 정의/호출 (FUNCTION, PROCEDURE)
|
|
[ ] LOCAL, STATIC, PRIVATE, PUBLIC 변수
|
|
[ ] 배열/해시 연산
|
|
[ ] 코드 블록 (기본)
|
|
[ ] BEGIN SEQUENCE / RECOVER
|
|
|
|
검증: 기본적인 Harbour 프로그램 100개 테스트
|
|
```
|
|
|
|
### Phase 3: RDD (Month 4-5)
|
|
|
|
```
|
|
목표: DBF 파일 읽기/쓰기
|
|
|
|
추가 구현:
|
|
[ ] hbrdd/workarea.go — 워크에어리어 관리
|
|
[ ] hbrdd/dbf.go — DBF 포맷
|
|
[ ] hbrdd/ntx.go — NTX 인덱스
|
|
[ ] hbrdd/cdx.go — CDX 인덱스
|
|
[ ] USE, APPEND, REPLACE, SEEK, INDEX ON
|
|
[ ] SET FILTER, SET RELATION
|
|
|
|
검증: 기존 DBF 데이터 파일로 CRUD 동작
|
|
```
|
|
|
|
### Phase 4: OOP + 매크로 (Month 6)
|
|
|
|
```
|
|
목표: 클래스 시스템과 매크로 동작
|
|
|
|
추가 구현:
|
|
[ ] hbrt/class.go — 클래스 정의/인스턴스
|
|
[ ] 연산자 오버로딩
|
|
[ ] 매크로 컴파일러 (미니 파서)
|
|
[ ] PP (전처리기)
|
|
|
|
검증: 실제 비즈니스 애플리케이션 PRG 컴파일
|
|
```
|
|
|
|
### Phase 5: Go 연동 (Month 7-8)
|
|
|
|
```
|
|
목표: Go 패키지를 PRG에서 사용
|
|
|
|
추가 구현:
|
|
[ ] IMPORT 문법
|
|
[ ] Go ↔ Five 타입 브릿지
|
|
[ ] hbweb — HTTP 서버/클라이언트
|
|
[ ] hbsql — SQL RDD (PostgreSQL, SQLite)
|
|
[ ] 동시성 프리미티브 (GO, CHANNEL, SEND, RECEIVE)
|
|
|
|
검증: REST API 서버를 PRG로 작성하여 배포
|
|
```
|
|
|
|
### Phase 6: 도구 + 생태계 (Month 9-10)
|
|
|
|
```
|
|
목표: 개발 경험 완성
|
|
|
|
추가 구현:
|
|
[ ] harbour fmt — 코드 포매터
|
|
[ ] harbour lsp — Language Server
|
|
[ ] harbour test — 테스트 프레임워크
|
|
[ ] harbour migrate — 마이그레이션 도구
|
|
[ ] VSCode 확장
|
|
[ ] 문서 사이트
|
|
|
|
검증: 실제 프로젝트에서 개발 → 빌드 → 배포 완전 사이클
|
|
```
|
|
|
|
### Phase 7: 언어 진화 (Month 11-12)
|
|
|
|
```
|
|
목표: Five 고유 기능 추가
|
|
|
|
추가 구현:
|
|
[ ] 타입 힌트 (선택적)
|
|
[ ] 다중 반환
|
|
[ ] 구조적 분해
|
|
[ ] 패턴 매칭
|
|
[ ] 호환성 모드 플래그
|
|
[ ] 추가 RDD 드라이버 (MongoDB, REST, Parquet)
|
|
|
|
검증: Five 쇼케이스 프로젝트 공개
|
|
```
|
|
|
|
---
|
|
|
|
## 변경 이력
|
|
|
|
| 날짜 | 변경 내용 |
|
|
|------|----------|
|
|
| 2026-03-27 | 초기 작성. Harbour+Go 융합 전략, 언어 진화, 생태계 설계 |
|