# 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 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 융합 전략, 언어 진화, 생태계 설계 |