docs: Add readability advantage — AI era code maintainability
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) <noreply@anthropic.com>
This commit is contained in:
243
docs/five-readability-en.md
Normal file
243
docs/five-readability-en.md
Normal file
@@ -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.**
|
||||
280
docs/five-readability-ko.md
Normal file
280
docs/five-readability-ko.md
Normal file
@@ -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가 만들어도 사람이 검증할 수 있는 유일한 시스템 언어입니다.**
|
||||
Reference in New Issue
Block a user