그누보드5는 왜 AI 개발 시 오류가 많을까? - gemini 버전 정보
그누보드5는 왜 AI 개발 시 오류가 많을까? - gemini 버전
본문
작성해주신 초안은 개발자 입장에서 구체적인 예시(코드)가 포함되어 있어 매우 설득력이 높습니다. 여기에 제가 앞서 분석했던 구조적/이론적 배경을 자연스럽게 녹여내어, SIR 커뮤니티 회원들이 읽기 좋게 다듬고 보완했습니다.
글자 수 제한 없이, 문제점 분석(Why) -> 구체적 예시(Code) -> 해결책(How) -> 결론의 논리적 흐름으로 구성했습니다.
제목: [개발팁] 그누보드5는 왜 AI(Cursor, GPT) 코딩 시 유독 오류가 많을까요?
안녕하세요, 개발자 여러분.
요즘 Claude, GPT-4, 그리고 Cursor 같은 AI 코딩 도구를 활용해서 개발하시는 분들 많으시죠? 저 또한 최근 그누보드5 기반 프로젝트에 AI 에이전트를 적극 도입하여 생산성을 높여보려 노력하고 있습니다.
그런데 Laravel이나 Spring Boot, 혹은 최신 Node.js 프레임워크를 다룰 때와 달리, 유독 그누보드5 환경에서 AI가 맥락을 못 잡거나 환각(Hallucination)을 일으키는 경우가 잦더군요.
"왜 그럴까?"를 곰곰이 분석해 보니, 그누보드5가 가진 2000년대 초반의 합리적인 설계 방식이 역설적으로 현대의 LLM(거대언어모델)이 코드를 이해하는 방식과는 상충하는 지점들이 있었습니다. 그 이유를 3가지로 정리해 공유해 봅니다.
1. DB 테이블 명세의 부재 (Explicit Schema vs Implicit Query)
AI가 데이터베이스 관련 코드를 짜려면 "이 테이블에 어떤 컬럼이 있고, 타입은 무엇인가?" 라는 정보가 필수적입니다.
Laravel은 마이그레이션 파일에, Spring은 Entity 클래스에 이 정보가 명시적으로 드러납니다. AI는 이 파일들을 읽고 "아, users 테이블에는 email 컬럼이 있구나"라고 확신을 갖습니다. 하지만 그누보드는 다릅니다.
// 그누보드5의 현실
sql_query("SELECT * FROM {$g5['member_table']} WHERE mb_id = '{$mb_id}'");
테이블 구조가 PHP 코드(Model) 어디에도 명시되어 있지 않습니다. g5_member 테이블에 mb_level이 있는지, mb_addr1이 있는지 AI는 알 길이 없습니다. 결국 AI는 문맥상 "아마 이런 컬럼이 있겠지..."라고 추측하게 되고, 여기서 없는 컬럼을 참조하거나 타입을 착각하는 오류가 발생합니다.
2. 동적 변수로 매핑되는 테이블 이름 (Runtime Evaluation)
이것이 AI 입장에서(특히 정적 분석 도구 입장에서) 가장 난감한 부분입니다.
PHP
// 일반적인 프레임워크
$posts = DB::table('posts')->where('id', $id)->get();
// 그누보드5
$write_table = $g5['write_prefix'] . $bo_table; // 런타임에 결정됨
$row = sql_fetch("SELECT * FROM {$write_table} WHERE wr_id = '{$wr_id}'");
그누보드5는 게시판 생성 시마다 g5_write_free, g5_write_notice 처럼 별도의 테이블을 생성합니다. AI 입장에서는:
-
$g5['write_prefix']가 무엇인지 모릅니다. (config나 common 파일을 다 뒤져야 함) -
$bo_table에 런타임 시점 어떤 값이 들어오는지 모릅니다. -
결국 "이 쿼리가 어떤 실제 테이블을 가리키는지" 코드만 봐선 확정할 수 없습니다.
이런 동적 구조는 유연하지만, AI가 코드의 흐름과 데이터의 관계를 추적하는 것을 끊어놓습니다.
3. 스킨 + 테마의 이중 렌더링과 Include 구조
그누보드5의 화면 출력 로직은 데이터 처리와 뷰(View)가 강하게 결합되어 있고, 파일 간 의존성이 복잡합니다.
Plaintext
요청 → bbs/board.php (Core)
→ lib/board.lib.php (Lib)
→ 테마 파일 (있으면)
→ 스킨 파일 (View + Logic)
PHP
// board.php 일부
if ($board_skin_path) {
include_once($board_skin_path.'/list.skin.php');
}
AI에게 "게시판 목록 디자인 좀 바꿔줘"라고 하면 AI는 혼란에 빠집니다.
-
파일 위치의 모호성: 테마를 쓰고 있는지, 기본 스킨을 쓰고 있는지 경로 추적이 어렵습니다.
-
변수의 출처:
list.skin.php에서 사용하는$list,$is_admin,$write등의 변수가 어느 파일에서 정의되어 넘어왔는지 추적하기 힘듭니다. (Scope가 전역적으로 얽혀 있음)
결국 AI는 엉뚱한 경로의 파일을 수정하라고 제안하거나, common.php에서 정의된 줄 모르는 변수를 스킨 파일 내에서 다시 정의하려 드는 실수를 범하게 됩니다.
💡 그럼 어떻게 해야 할까요? (소소한 팁)
그누보드 환경에서 AI 코딩 효율을 높이려면, 우리가 AI에게 **"친절한 가이드"**가 되어야 합니다. 저는 다음과 같은 방식으로 해결하고 있습니다.
1. 테이블 명세(DDL)를 컨텍스트로 제공하세요. 프롬프트나 프로젝트 참조 파일에 주요 테이블 스키마를 넣어주면 환각이 확연히 줄어듭니다.
SQL
-- cursorrules나 별도 md파일에 저장
CREATE TABLE g5_write_default (
wr_id int(11) NOT NULL auto_increment,
wr_subject varchar(255) NOT NULL,
wr_content text NOT NULL,
-- ...
);
2. 변수 매핑 정보를 미리 알려주세요.
PHP
// AI에게 주는 힌트
"이 프로젝트에서 $g5['member_table']은 실제 DB의 'g5_member' 테이블을 의미해."
"$write_table 변수는 현재 게시판의 테이블명(예: g5_write_free)을 의미해."
3. 프로젝트 구조를 설명하세요. "현재 theme/basic 테마를 사용 중이고, 수정하려는 게시판 스킨은 theme/basic/skin/board/gallery 경로에 있어"라고 명시해주면 파일 경로 오류를 막을 수 있습니다.
마치며
그누보드5의 구조가 나쁘다는 뜻은 결코 아닙니다. 2000년대 PHP 생태계에서는 가장 효율적이고 합리적인 설계였고, 덕분에 지금까지 수많은 사이트가 안정적으로 돌아가고 있습니다.
다만, **"명시적 선언", "정적 분석 가능성", "관심사의 분리"**를 좋아하는 최신 AI 도구들과 합을 맞추기에는 구조적으로 불리한 면이 있다는 사실을 인지하고 접근하면 좋을 것 같습니다. 그누보드6나 영카트6에서는 이런 모던한 구조들이 반영되어 AI와 함께 코딩하기 더 즐거운 환경이 되기를 기대해 봅니다.
혹시 그누보드로 AI 코딩하시면서 저와 비슷한 경험이나 나만의 노하우가 있으신 분들은 댓글로 공유 부탁드립니다! 🙏
(P.S. 저는 요즘 그누보드 플러그인 개발 시 AI에게 주입할 'Context 문서'를 템플릿화해서 쓰고 있는데, 확실히 오류가 줄더군요. 관심 있는 분들이 계시면 나중에 이 템플릿도 정리해서 올려보겠습니다.)
0
댓글 2개
예전에 웹접근성 작업할때 생각이 나네요.
그누보드의 개발된지 역사적으로 꽤 긴 시간입니다.
그런데도 불구하고 주석이나 웹접근성 부분에서는 만족할만한 수준은 못되죠.
단적인 예로....
CREATE TABLE IF NOT EXISTS `g5_auth` (
`mb_id` varchar(20) NOT NULL default '',
`au_menu` varchar(50) NOT NULL default '',
`au_auth` set('r','w','d') NOT NULL default '',
PRIMARY KEY (`mb_id`,`au_menu`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
위의 쿼리문을 아래와 같이 작성해 줬더라면....
CREATE TABLE IF NOT EXISTS `g5_auth` (
`mb_id` varchar(20) NOT NULL DEFAULT '' COMMENT '회원 아이디',
`au_menu` varchar(50) NOT NULL DEFAULT '' COMMENT '권한 메뉴',
`au_auth` set('r','w','d') NOT NULL DEFAULT '' COMMENT '권한(r:읽기, w:쓰기, d:삭제)',
PRIMARY KEY (`mb_id`, `au_menu`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='관리자 권한 테이블';
그것은 사용자 몫으로 남겨둔것 같습니다.^^
