Files
five/docs/five-readability-ko.md
Charles KWON OhJun d774f1598c docs: Fix readability docs — Five supports DEFER too
Five's DEFER is Go's defer in PRG syntax.
Same safety guarantee, but without if err != nil pollution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:57:47 +09:00

7.7 KiB

Five의 가독성 — AI 시대의 진짜 강점

AI가 코딩하는 시대, 왜 가독성이 중요한가

AI가 코드를 자동 생성하는 시대입니다. 하지만 문제가 있습니다:

  1. AI가 복잡한 코드를 만들어냄 — 정상 동작하지만 사람이 이해 못 함
  2. AI 없이 유지보수 불가 — AI 서비스 중단 시 코드가 블랙박스가 됨
  3. 버그 발견이 어려움 — 코드를 읽을 수 없으면 버그도 못 찾음
  4. 팀 협업 불가 — 작성자 외에 누구도 코드를 이해 못 함

Five는 이 문제를 근본적으로 해결합니다.

같은 일, 다른 가독성

고객 목록 조회

// Five (PRG)
USE customers NEW
SET FILTER TO balance > 10000
GO TOP
DO WHILE !Eof()
   ? name, city, balance
   SKIP
ENDDO
// 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
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
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. 영어 문장처럼 읽힌다

USE customers NEW                    // 고객 파일 열어
GO TOP                               // 처음으로 가
DO WHILE !Eof()                      // 끝까지 반복해
   IF balance > 10000                // 잔액이 만 넘으면
      ? name, balance                // 이름이랑 잔액 출력해
   ENDIF                             // 조건 끝
   SKIP                              // 다음으로
ENDDO                                // 반복 끝

프로그래밍을 모르는 사람도 흐름이 보입니다. {, }, :=, ->, func, defer 같은 기호가 없습니다.

2. 모든 것이 명시적이다

// Five — 끝이 명확함
IF condition
   ...
ENDIF                // IF가 여기서 끝남

FOR i := 1 TO 10
   ...
NEXT                 // FOR가 여기서 끝남

DO WHILE condition
   ...
ENDDO                // WHILE이 여기서 끝남
// Go — } 가 뭘 닫는 건지 세어야 함
if condition {
    for i := 0; i < 10; i++ {
        if another {
            // ...
        }     // ← 이 } 는 inner if
    }         // ← 이 } 는 for
}             // ← 이 } 는 outer if

3. 변수명이 길어도 자연스럽다

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. DEFER로 안전하면서도 깔끔하다

// Go — defer는 있지만 err 체크가 코드를 오염
db, err := sql.Open("sqlite3", dsn)
if err != nil {
    return fmt.Errorf("open failed: %w", err)
}
defer db.Close()
result, err := db.Query("SELECT ...")
if err != nil {
    return fmt.Errorf("query failed: %w", err)
}
defer result.Close()
// Five — DEFER + 깔끔한 비즈니스 로직
db := sql.Open("sqlite", dsn)
DEFER db:Close()                     // Go의 defer와 동일!

result := SqlScan(db, "SELECT ...")
// 에러는 BEGIN SEQUENCE로 한 곳에서 처리
// 그런데 코드는 읽기 쉬움

Five는 Go의 deferDEFER로 그대로 지원합니다. Go의 좋은 점은 가져오되, if err != nil 반복은 없앱니다.

AI 시대 시나리오

시나리오 1: AI 서비스가 중단됨

Go/Python/Java 프로젝트:

  • 10만 줄 코드 — 구조 파악에 수일
  • 복잡한 타입 시스템, 제네릭, 인터페이스
  • 프레임워크 의존성 파악 필요
  • 신규 개발자가 인수하려면 수주일

Five 프로젝트:

  • 같은 기능이 3만 줄 — 코드량 자체가 적음
  • USE, SKIP, SEEK — 명령어가 의미 그대로
  • 경험 없는 개발자도 하루 만에 코드 읽기 가능

시나리오 2: 긴급 버그 수정

// 버그가 여기 있다고 가정
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가 만든 코드 검증

// 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가 쉬운 것만으로 충분한 게 아닙니다. 쉬운 코드로 강력한 기능을 쓸 수 있어야 합니다.

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가 만들어도 사람이 검증할 수 있는 유일한 시스템 언어입니다.