Backend
home
🏛️

Delphi의 기본 구조와 문법, 그리고 웹 전환 가능성

생성일
2026/04/13 08:43
태그
Delphi
회사에서 Delphi로 작성된 레거시 시스템을 유지보수하다 보면 자연스럽게 이런 생각이 든다. "이걸 웹으로 옮길 수 있을까?" 오늘은 Delphi가 어떤 언어인지 기본 구조부터 정리하고, 실제로 웹 전환이 가능한지, 가능하다면 어떤 방식으로 진행해야 하는지 직접 고민한 내용을 정리해봤다.

1. Delphi란 무엇인가

Delphi는 Borland가 1995년 처음 출시한 Object Pascal 기반의 RAD(Rapid Application Development) 도구다. 지금은 Embarcadero Technologies가 관리하고 있다. Windows 데스크톱 애플리케이션 개발에 특화되어 있고, VCL(Visual Component Library)이라는 강력한 UI 컴포넌트 시스템을 제공한다.
국내에서는 특히 금융, 제조, 의료 분야의 사내 시스템에 Delphi로 만들어진 레거시가 꽤 많이 남아 있다. 개발 속도가 빠르고 컴파일된 실행파일 하나로 배포가 된다는 장점 덕분에 2000년대 초반까지 많이 쓰였다.

2. Delphi의 기본 구조와 문법

프로젝트 구조

Delphi 프로젝트는 크게 세 가지 파일로 구성된다.
.dpr — 프로젝트 파일. 진입점(Entry Point)이 여기 있다.
.pas — Pascal 소스 파일. 실제 로직이 담긴다.
.dfm — Form 정의 파일. UI 컴포넌트 배치와 속성이 저장된다.

기본 문법 구조

unit UserService; interface uses SysUtils, Classes; type TUser = class private FName: string; FAge: Integer; public constructor Create(const AName: string; AAge: Integer); function GetInfo: string; property Name: string read FName write FName; property Age: Integer read FAge write FAge; end; implementation constructor TUser.Create(const AName: string; AAge: Integer); begin FName := AName; FAge := AAge; end; function TUser.GetInfo: string; begin Result := Format('%s (%d세)', [FName, FAge]); end; end.
Pascal
복사
Java나 C#과 비교하면 문법이 장황한 편이지만 구조는 비슷하다. interface 섹션에서 선언하고, implementation 섹션에서 구현하는 방식이다.

이벤트 기반 UI 처리

Delphi의 핵심은 이벤트 핸들러다. 버튼 클릭 하나가 이런 식으로 연결된다.
procedure TForm1.Button1Click(Sender: TObject); var UserName: string; begin UserName := Edit1.Text; if UserName = '' then begin ShowMessage('이름을 입력해주세요.'); Exit; end; Label1.Caption := '안녕하세요, ' + UserName + '!'; end;
Pascal
복사

DB 연동 방식

Delphi는 TDataSet, TQuery, TADOConnection 같은 컴포넌트로 DB와 직접 연결한다. UI 컴포넌트와 DB를 데이터바인딩으로 연결하는 방식이 특징이다.
procedure TForm1.LoadUsers; begin ADOQuery1.SQL.Text := 'SELECT * FROM users WHERE active = 1'; ADOQuery1.Open; // DBGrid1에 자동으로 데이터가 표시됨 (데이터바인딩) end;
Pascal
복사

3. 웹 전환 가능성 — 현실적으로 따져보기

결론부터 말하면 전환은 가능하지만, 방식에 따라 난이도와 결과물이 크게 달라진다.

Delphi 웹 전환이 어려운 이유

VCL 의존성: UI가 Windows GDI 기반 컴포넌트에 강하게 결합되어 있어 그대로 브라우저로 옮길 수 없다.
비즈니스 로직과 UI의 혼재: 이벤트 핸들러 안에 DB 쿼리, 계산 로직, 화면 제어가 뒤섞여 있는 경우가 많다.
Pascal 문법: 현재 웹 생태계에서 Pascal을 직접 다루는 프레임워크가 거의 없다.

전환 전략 3가지

① Delphi 자체 웹 프레임워크 활용 (낮은 전환 비용)
Embarcadero는 IntraWeb, TMS Web Core 같은 웹 지원 도구를 제공한다. 기존 Delphi 코드를 최대한 재활용하면서 웹으로 배포할 수 있다.
장점: 기존 Pascal 코드 재사용 가능, 러닝 커브 낮음
단점: 결과물이 현대적인 웹 UX와 거리가 있고, 생태계가 협소하다
② 백엔드는 Delphi 유지, 프론트엔드만 웹으로 교체 (권장)
가장 현실적인 접근법이다. Delphi의 비즈니스 로직은 REST API 서버로 전환하고, 프론트엔드는 React나 Vue로 새로 만드는 방식이다.
// Delphi REST API 서버 예시 (DataSnap 또는 RAD Server 사용) procedure TServerMethods.GetUsers; var Result: TJSONArray; begin // DB 조회 후 JSON으로 응답 Result := TJSONArray.Create; // ... 로직 Response.Body.SetValue(Result, True); end;
Pascal
복사
프론트엔드에서는 이 API를 호출하면 된다.
// React + TypeScript에서 Delphi API 호출 const fetchUsers = async () => { const res = await fetch('http://legacy-server/api/users'); const data = await res.json(); return data; };
TypeScript
복사
장점: 기존 로직 검증된 상태로 유지, 프론트만 점진적으로 교체 가능
단점: Delphi 서버 유지보수 인력 필요, 두 기술 스택 병행 운영
③ 전면 재작성 (높은 비용, 장기 프로젝트)
비즈니스 로직까지 전부 Node.js, Java, .NET 등으로 재작성하는 방식이다. 가장 깔끔하지만 리스크도 크다.
장점: 기술 부채 완전 청산, 현대적인 스택으로 전환
단점: 기간과 비용이 크고, 기존 로직을 빠짐없이 재현하는 것이 어렵다

4. 실제 전환 진행 시 체크리스트

전환을 결정했다면 아래 순서로 접근하는 게 현실적이다.
1단계: 현황 파악
전체 Form 수, 이벤트 핸들러 수 파악
DB 연결 방식 확인 (BDE, ADO, FireDAC 등)
외부 컴포넌트 라이선스 확인
2단계: 비즈니스 로직 분리
UI 코드와 로직 코드를 분리하는 리팩터링 선행
이벤트 핸들러 안에 박혀 있는 DB 쿼리를 Service 레이어로 분리
3단계: API 레이어 구성
DataSnap, RAD Server, 또는 mORMot 같은 프레임워크로 REST API 노출
인증(JWT 등) 처리 추가
4단계: 프론트엔드 개발
React + TypeScript로 화면 단위 재개발
기존 화면과 1:1 대응보다 UX 재설계를 권장
5단계: 병행 운영 후 전환
구버전 Delphi 클라이언트와 신규 웹 버전을 일정 기간 병행
기능 검증 완료 후 순차 전환

6. C#/.NET으로 전환하면 React가 필요 없을까?

Delphi 웹 전환을 고민하다 보면 자연스럽게 이런 질문이 생긴다. "그냥 C#으로 다 하면 안 되나?"
결론부터 말하면 가능하다. Microsoft의 Blazor를 쓰면 C# 하나로 프론트엔드까지 커버할 수 있어서, React나 Vue 같은 JavaScript 프레임워크를 별도로 배울 필요가 없다.

Blazor란

Blazor는 .NET 기반의 공식 웹 UI 프레임워크다. C# 코드로 컴포넌트를 작성하면 브라우저에서 동작하는 웹 앱이 된다.
// Blazor 컴포넌트 예시 — C#만으로 UI 작성 @page "/users" @inject UserService UserService @foreach (var user in users) { <div>@user.Name — @user.Email</div> } @code { private List<User> users = new(); protected override async Task OnInitializedAsync() => users = await UserService.GetAllAsync(); }
C#
복사
React의 useState + useEffect 조합과 역할이 같지만, 언어는 C#이다. 팀 전체가 C# 개발자라면 JavaScript 학습 비용 없이 웹 전환이 가능하다.

ASP.NET Core — 기존 로직 재사용이 핵심

Delphi와 달리 C# 코드는 레이어 분리가 자연스럽다. 기존 비즈니스 로직 클래스를 그대로 두고, 컨트롤러 레이어만 씌우면 REST API 서버가 된다.
// 기존 C# 서비스 클래스 → 변경 없이 재사용 [ApiController] [Route("api/[controller]")] public class UsersController : ControllerBase { private readonly UserService _userService; public UsersController(UserService userService) => _userService = userService; [HttpGet] public IActionResult GetUsers() => Ok(_userService.GetAll()); }
C#
복사

Java 백엔드와의 연동

백엔드를 Java(Spring 등)로 운영하고 있어도 연동에 전혀 문제없다. Blazor 프론트엔드는 결국 HTTP로 API를 호출하는 클라이언트이기 때문에, 백엔드가 Java든 .NET이든 REST API 규격만 맞으면 된다.
// Blazor에서 Java Spring API 호출 @inject HttpClient Http @code { private List<Order> orders = new(); protected override async Task OnInitializedAsync() { // Java 백엔드 API 엔드포인트 호출 orders = await Http.GetFromJsonAsync<List<Order>>("https://java-api.example.com/api/orders"); } }
C#
복사
Java 백엔드가 JSON을 반환하면 Blazor가 그걸 받아서 화면에 뿌리면 끝이다. 언어 간 장벽이 없다.

Delphi vs C#/.NET 웹 전환 비교

Delphi
C#/.NET
언어 생태계
Pascal, 웹 프레임워크 거의 없음
C#, 웹 프레임워크 풍부
로직 재사용
어려움 (UI에 혼재)
쉬움 (레이어 분리가 자연스러움)
프론트 전환
React 등 별도 언어 필요
Blazor로 C# 유지 가능
Java 연동
REST API로 가능하나 생태계 협소
REST API로 자연스럽게 연동
클라우드/Linux
사실상 불가
공식 지원
Delphi 레거시를 안고 가야 하는 상황이라면, 장기적으로는 C#/.NET 스택으로의 전환이 가장 현실적인 출구 전략이 될 수 있다.

7. Delphi에서 C# WinForms로 — 가장 현실적인 전환 경로

Delphi VCL과 구조가 가장 비슷한 게 WinForms다. 드래그앤드롭으로 UI를 배치하고 이벤트 핸들러를 연결하는 방식이 거의 동일해서, Delphi 개발자가 가장 빠르게 적응할 수 있는 선택지다.

UI 컴포넌트 1:1 대응

Delphi VCL
C# WinForms
TForm
Form
TButton
Button
TEdit
TextBox
TLabel
Label
TDBGrid
DataGridView
TComboBox
ComboBox
TPanel
Panel
TDateTimePicker
DateTimePicker
TMainMenu
MenuStrip
데이터바인딩
BindingSource
거의 모든 VCL 컴포넌트가 WinForms에 대응하는 컨트롤로 존재한다. Visual Studio의 디자이너 툴도 Delphi Form 편집기와 사용 방식이 유사하다.

이벤트 핸들러 구조 비교

Delphi에서 이런 코드가 있었다면:
procedure TForm1.btnLoadClick(Sender: TObject); begin ADOQuery1.SQL.Text := 'SELECT * FROM users WHERE active = 1'; ADOQuery1.Open; DBGrid1.DataSource := DataSource1; end;
Pascal
복사
WinForms에서는 이렇게 쓴다:
private void btnLoad_Click(object sender, EventArgs e) { var users = _userService.GetActiveUsers(); dataGridView1.DataSource = users; // 데이터바인딩 동일 }
C#
복사
구조가 거의 같아서 Delphi 코드를 보면서 WinForms로 옮기는 게 크게 어렵지 않다.

Java 백엔드 서비스 ID 호출

Java 쪽에서 서비스 ID 기반 인증을 쓰고 있다면 WinForms에서도 동일하게 호출할 수 있다.
// API Key / 서비스 ID 방식 private async Task<List<Order>> LoadOrdersAsync() { using var client = new HttpClient(); client.DefaultRequestHeaders.Add("X-Service-ID", "your-service-id"); client.DefaultRequestHeaders.Add("X-API-Key", "your-api-key"); var orders = await client.GetFromJsonAsync<List<Order>>( "https://java-api.example.com/api/orders" ); return orders ?? new List<Order>(); } // WinForms 버튼 클릭에서 호출 private async void btnLoad_Click(object sender, EventArgs e) { var orders = await LoadOrdersAsync(); dataGridView1.DataSource = orders; }
C#
복사
JWT 토큰 방식이라면:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _tokenService.GetToken());
C#
복사
Java 백엔드가 어떤 인증 방식을 쓰든 HTTP 헤더에 실어 보내는 건 동일하다. WinForms에서 HttpClient 하나로 전부 처리 가능하다.

WinForms 전환 시 권장 구조

Delphi처럼 이벤트 핸들러에 모든 걸 몰아넣기보다, 처음부터 레이어를 나눠두면 나중에 웹 전환도 훨씬 수월해진다.
// Form은 UI만 담당 private async void btnLoad_Click(object sender, EventArgs e) { var users = await _userService.GetAllAsync(); // 로직은 Service에 dataGridView1.DataSource = users; }
C#
복사
이 구조면 나중에 WinForms를 Blazor로 교체할 때 Service/Repository 레이어는 그대로 재사용할 수 있다.

마치며

Delphi는 낡은 기술처럼 보이지만, 지금도 내부에서 돌아가는 시스템이 많다. 무조건 버리기보다는 어떤 방식으로 현대화할지 전략을 세우는 게 중요하다. 당장 전면 재작성이 어렵다면 백엔드는 Delphi REST API로 유지하면서 프론트엔드부터 React로 교체하는 방식이 가장 현실적인 출발점이 될 것 같다.

참고 자료

Martin Fowler, Strangler Fig Application 패턴 — 레거시 시스템을 점진적으로 교체하는 전략으로, Delphi 전환에도 직접 적용 가능하다.