From b1a58724c8fdd8256c3d78440688ccab1dc065c1 Mon Sep 17 00:00:00 2001 From: Charles KWON OhJun Date: Tue, 31 Mar 2026 09:53:58 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20Add=20readability=20advantage=20?= =?UTF-8?q?=E2=80=94=20AI=20era=20code=20maintainability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five's hidden strength: PRG code is readable by non-developers. When AI generates code, humans must verify it. Five's xBase syntax makes this possible. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/five-readability-en.md | 243 +++++++++++++++++++++++++++++++ docs/five-readability-ko.md | 280 ++++++++++++++++++++++++++++++++++++ 2 files changed, 523 insertions(+) create mode 100644 docs/five-readability-en.md create mode 100644 docs/five-readability-ko.md diff --git a/docs/five-readability-en.md b/docs/five-readability-en.md new file mode 100644 index 0000000..fa5f8a0 --- /dev/null +++ b/docs/five-readability-en.md @@ -0,0 +1,243 @@ +# Five's Readability — The Real Advantage in the AI Era + +## Why Readability Matters When AI Writes Code + +AI generates code automatically now. +But there's a problem: + +1. **AI creates complex code** — it works, but humans can't understand it +2. **Unmaintainable without AI** — if the AI service goes down, code becomes a black box +3. **Bugs hide in complexity** — if you can't read it, you can't debug it +4. **Team collaboration breaks** — nobody except the AI understands the code + +**Five solves this fundamentally.** + +## Same Task, Different Readability + +### Query Customer List + +```prg +// Five (PRG) — 8 lines +USE customers NEW +SET FILTER TO balance > 10000 +GO TOP +DO WHILE !Eof() + ? name, city, balance + SKIP +ENDDO +``` + +```go +// Go — 27 lines +func listCustomers() { + db, err := sql.Open("sqlite3", "customers.db") + if err != nil { + log.Fatal(err) + } + defer db.Close() + rows, err := db.Query( + "SELECT name, city, balance FROM customers WHERE balance > $1", + 10000, + ) + if err != nil { + log.Fatal(err) + } + defer rows.Close() + for rows.Next() { + var name, city string + var balance float64 + if err := rows.Scan(&name, &city, &balance); err != nil { + log.Fatal(err) + } + fmt.Println(name, city, balance) + } + if err := rows.Err(); err != nil { + log.Fatal(err) + } +} +``` + +| Language | Lines | Error handling | Non-developer readable | +|----------|------|---------------|:---:| +| **Five (PRG)** | **8** | Built-in | **Yes** | +| Python | 12 | Manual | Maybe | +| Go | 27 | Required | No | +| Java | 15 | Required | No | + +## Why PRG is Easy to Read + +### 1. Reads like English sentences + +```prg +USE customers NEW // Open customer file +GO TOP // Go to the first record +DO WHILE !Eof() // Repeat until end of file + IF balance > 10000 // If balance exceeds 10000 + ? name, balance // Print name and balance + ENDIF // End condition + SKIP // Move to next record +ENDDO // End loop +``` + +Even non-programmers can follow the flow. +No `{`, `}`, `func`, `defer`, or cryptic symbols. + +### 2. Everything is explicit + +```prg +// Five — endings are clear +IF condition + ... +ENDIF // IF ends here + +FOR i := 1 TO 10 + ... +NEXT // FOR ends here + +DO WHILE condition + ... +ENDDO // WHILE ends here +``` + +```go +// Go — count the braces +if condition { + for i := 0; i < 10; i++ { + if another { + // ... + } // ← which one does this close? + } // ← this one? +} // ← or this one? +``` + +### 3. Variable names tell their type + +```prg +LOCAL cCustomerName, nTotalBalance, dLastPurchase, lIsActive + +cCustomerName := "Charles Kwon" // c = Character +nTotalBalance := 15000.50 // n = Numeric +dLastPurchase := Date() // d = Date +lIsActive := .T. // l = Logical +``` + +Hungarian notation makes types visible in names: +- `c` = Character (string) +- `n` = Numeric (number) +- `d` = Date +- `l` = Logical (boolean) +- `a` = Array +- `o` = Object + +Even AI-generated code is self-documenting with these prefixes. + +### 4. Error handling doesn't pollute business logic + +```go +// Go — more error handling than business logic +result, err := doSomething() +if err != nil { + return fmt.Errorf("doSomething failed: %w", err) +} +result2, err := doAnother(result) +if err != nil { + return fmt.Errorf("doAnother failed: %w", err) +} +``` + +```prg +// Five — focus on business logic +result := doSomething() +result2 := doAnother(result) +// Errors handled in one place via BEGIN SEQUENCE or ErrorBlock +``` + +## AI-Era Scenarios + +### Scenario 1: AI service goes down + +**Go/Python/Java project:** +- 100K lines — days to understand structure +- Complex type systems, generics, interfaces +- Framework dependencies to untangle +- New developer needs weeks to onboard + +**Five project:** +- Same features in 30K lines — less code to read +- `USE`, `SKIP`, `SEEK` — commands mean what they say +- Inexperienced developer can read code in one day + +### Scenario 2: Emergency bug fix + +```prg +// Assume the bug is here +USE orders NEW +SET FILTER TO date >= Date() - 30 +GO TOP +DO WHILE !Eof() + IF amount > 0 + nTotal += amount // ← bug here: should be = instead of +=? + ENDIF + SKIP +ENDDO +``` + +Non-developers (sales team, managers) can read this and understand +"nTotal is accumulating something." This level of comprehension is +impossible with Go code. + +### Scenario 3: Verifying AI-generated code + +```prg +// AI-generated Five code — humans can verify +FUNCTION CalcDiscount(nPrice, nQuantity) + LOCAL nDiscount + IF nQuantity >= 100 + nDiscount := nPrice * 0.15 // 100+ units: 15% discount + ELSEIF nQuantity >= 50 + nDiscount := nPrice * 0.10 // 50+ units: 10% discount + ELSE + nDiscount := 0 // No discount + ENDIF + RETURN nDiscount +``` + +A business stakeholder can look at this code and ask: +"Is 15% for 100+ units correct?" — try doing that with Go generics. + +## Five + Go = The Optimal Combination + +Simplicity alone isn't enough. +**Simple code with powerful capabilities** — that's the goal. + +```prg +IMPORT "database/sql" +IMPORT _ "modernc.org/sqlite" + +PROCEDURE Main() + LOCAL db, aRows, i + + db := sql.Open("sqlite", ":memory:") + DEFER db:Close() + + db:Exec("CREATE TABLE orders (id INTEGER, amount REAL)") + db:Exec("INSERT INTO orders VALUES (1, 15000)") + + aRows := SqlScan(db, "SELECT * FROM orders") + FOR i := 1 TO Len(aRows) + ? aRows[i]["id"], aRows[i]["amount"] + NEXT + + RETURN +``` + +SQL database access in PRG syntax. +Go's `database/sql` powers it behind the scenes, +but the person reading this code **doesn't need to know Go**. + +## The Bottom Line + +> **In an era where AI writes code, +> code that humans can read is the real asset. +> Five is the only systems language where AI-generated code +> can be verified by humans — even non-developers.** diff --git a/docs/five-readability-ko.md b/docs/five-readability-ko.md new file mode 100644 index 0000000..0d73d9c --- /dev/null +++ b/docs/five-readability-ko.md @@ -0,0 +1,280 @@ +# Five의 가독성 — AI 시대의 진짜 강점 + +## AI가 코딩하는 시대, 왜 가독성이 중요한가 + +AI가 코드를 자동 생성하는 시대입니다. +하지만 문제가 있습니다: + +1. **AI가 복잡한 코드를 만들어냄** — 정상 동작하지만 사람이 이해 못 함 +2. **AI 없이 유지보수 불가** — AI 서비스 중단 시 코드가 블랙박스가 됨 +3. **버그 발견이 어려움** — 코드를 읽을 수 없으면 버그도 못 찾음 +4. **팀 협업 불가** — 작성자 외에 누구도 코드를 이해 못 함 + +**Five는 이 문제를 근본적으로 해결합니다.** + +## 같은 일, 다른 가독성 + +### 고객 목록 조회 + +```prg +// Five (PRG) +USE customers NEW +SET FILTER TO balance > 10000 +GO TOP +DO WHILE !Eof() + ? name, city, balance + SKIP +ENDDO +``` + +```go +// Go +func listCustomers() { + db, err := sql.Open("sqlite3", "customers.db") + if err != nil { + log.Fatal(err) + } + defer db.Close() + + rows, err := db.Query( + "SELECT name, city, balance FROM customers WHERE balance > $1", + 10000, + ) + if err != nil { + log.Fatal(err) + } + defer rows.Close() + + for rows.Next() { + var name, city string + var balance float64 + if err := rows.Scan(&name, &city, &balance); err != nil { + log.Fatal(err) + } + fmt.Println(name, city, balance) + } + if err := rows.Err(); err != nil { + log.Fatal(err) + } +} +``` + +```python +# Python +import sqlite3 + +def list_customers(): + conn = sqlite3.connect('customers.db') + cursor = conn.cursor() + cursor.execute( + 'SELECT name, city, balance FROM customers WHERE balance > ?', + (10000,) + ) + for row in cursor.fetchall(): + print(row[0], row[1], row[2]) + conn.close() +``` + +```java +// Java +public void listCustomers() throws SQLException { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:customers.db"); + PreparedStatement stmt = conn.prepareStatement( + "SELECT name, city, balance FROM customers WHERE balance > ?")) { + stmt.setDouble(1, 10000); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + System.out.println( + rs.getString("name") + " " + + rs.getString("city") + " " + + rs.getDouble("balance") + ); + } + } + } +} +``` + +| 언어 | 줄 수 | 에러 처리 | 비개발자 이해 | +|------|------|----------|:---:| +| **Five (PRG)** | **8** | 내장 | **✅ 가능** | +| Python | 12 | 수동 | △ | +| Go | 27 | 필수 | ❌ | +| Java | 15 | 필수 | ❌ | + +## PRG가 읽기 쉬운 이유 + +### 1. 영어 문장처럼 읽힌다 + +```prg +USE customers NEW // 고객 파일 열어 +GO TOP // 처음으로 가 +DO WHILE !Eof() // 끝까지 반복해 + IF balance > 10000 // 잔액이 만 넘으면 + ? name, balance // 이름이랑 잔액 출력해 + ENDIF // 조건 끝 + SKIP // 다음으로 +ENDDO // 반복 끝 +``` + +프로그래밍을 모르는 사람도 흐름이 보입니다. +`{`, `}`, `:=`, `->`, `func`, `defer` 같은 기호가 없습니다. + +### 2. 모든 것이 명시적이다 + +```prg +// Five — 끝이 명확함 +IF condition + ... +ENDIF // IF가 여기서 끝남 + +FOR i := 1 TO 10 + ... +NEXT // FOR가 여기서 끝남 + +DO WHILE condition + ... +ENDDO // WHILE이 여기서 끝남 +``` + +```go +// Go — } 가 뭘 닫는 건지 세어야 함 +if condition { + for i := 0; i < 10; i++ { + if another { + // ... + } // ← 이 } 는 inner if + } // ← 이 } 는 for +} // ← 이 } 는 outer if +``` + +### 3. 변수명이 길어도 자연스럽다 + +```prg +LOCAL cCustomerName, nTotalBalance, dLastPurchase, lIsActive + +cCustomerName := "Charles Kwon" +nTotalBalance := 15000.50 +dLastPurchase := Date() +lIsActive := .T. +``` + +헝가리안 표기법으로 변수 타입이 이름에 보입니다: +- `c` = Character (문자열) +- `n` = Numeric (숫자) +- `d` = Date (날짜) +- `l` = Logical (논리값) +- `a` = Array (배열) +- `o` = Object (객체) + +AI가 코드를 작성해도, 변수명만 보면 타입을 알 수 있습니다. + +### 4. 에러 처리가 코드를 오염시키지 않는다 + +```go +// Go — 비즈니스 로직보다 에러 처리가 더 많음 +result, err := doSomething() +if err != nil { + return fmt.Errorf("doSomething failed: %w", err) +} +result2, err := doAnother(result) +if err != nil { + return fmt.Errorf("doAnother failed: %w", err) +} +``` + +```prg +// Five — 비즈니스 로직에 집중 +result := doSomething() +result2 := doAnother(result) +// 에러는 BEGIN SEQUENCE나 ErrorBlock으로 한 곳에서 처리 +``` + +## AI 시대 시나리오 + +### 시나리오 1: AI 서비스가 중단됨 + +**Go/Python/Java 프로젝트:** +- 10만 줄 코드 — 구조 파악에 수일 +- 복잡한 타입 시스템, 제네릭, 인터페이스 +- 프레임워크 의존성 파악 필요 +- 신규 개발자가 인수하려면 수주일 + +**Five 프로젝트:** +- 같은 기능이 3만 줄 — 코드량 자체가 적음 +- `USE`, `SKIP`, `SEEK` — 명령어가 의미 그대로 +- 경험 없는 개발자도 하루 만에 코드 읽기 가능 + +### 시나리오 2: 긴급 버그 수정 + +```prg +// 버그가 여기 있다고 가정 +USE orders NEW +SET FILTER TO date >= Date() - 30 +GO TOP +DO WHILE !Eof() + IF amount > 0 + nTotal += amount // ← 여기가 문제: += 대신 = 써야 함? + ENDIF + SKIP +ENDDO +``` + +비개발자(영업팀, 관리자)도 코드를 읽고 "nTotal이 누적되는 것 같다"를 이해합니다. +Go 코드에서는 이 수준의 이해가 불가능합니다. + +### 시나리오 3: AI가 만든 코드 검증 + +```prg +// AI가 생성한 Five 코드 — 사람이 검증 가능 +FUNCTION CalcDiscount(nPrice, nQuantity) + LOCAL nDiscount + IF nQuantity >= 100 + nDiscount := nPrice * 0.15 // 100개 이상 15% 할인 + ELSEIF nQuantity >= 50 + nDiscount := nPrice * 0.10 // 50개 이상 10% 할인 + ELSE + nDiscount := 0 // 할인 없음 + ENDIF + RETURN nDiscount +``` + +비즈니스 담당자가 이 코드를 보고 "100개 이상이면 15% 맞아?"라고 확인할 수 있습니다. + +## Five + Go = 최적의 조합 + +Five가 쉬운 것만으로 충분한 게 아닙니다. +**쉬운 코드로 강력한 기능**을 쓸 수 있어야 합니다. + +```prg +IMPORT "database/sql" +IMPORT _ "modernc.org/sqlite" + +PROCEDURE Main() + LOCAL db, aRows, i + + // SQL — 쉬운 PRG 문법으로 + db := sql.Open("sqlite", ":memory:") + DEFER db:Close() + + db:Exec("CREATE TABLE orders (id INTEGER, amount REAL)") + db:Exec("INSERT INTO orders VALUES (1, 15000)") + + // 결과를 Harbour 배열로 받아서 xBase 스타일로 처리 + aRows := SqlScan(db, "SELECT * FROM orders") + FOR i := 1 TO Len(aRows) + ? aRows[i]["id"], aRows[i]["amount"] + NEXT + + RETURN +``` + +PRG 문법으로 SQL 데이터베이스를 씁니다. +Go의 `database/sql` 패키지가 뒤에서 동작하지만, +코드를 읽는 사람은 **Go를 몰라도** 됩니다. + +## 한 줄 요약 + +> **AI가 코드를 만들어주는 시대에, +> 사람이 읽을 수 있는 코드가 진짜 자산입니다. +> Five는 AI가 만들어도 사람이 검증할 수 있는 유일한 시스템 언어입니다.**