해결된 문제를 재발명하기: Odoo OWL 프론트엔드 프레임워크에 대한 아키텍처 리뷰

발행: (2026년 1월 19일 오전 04:39 GMT+9)
16 min read
원문: Dev.to

Source: Dev.to

번역할 텍스트가 제공되지 않았습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.

Introduction

이 글에서는 Odoo의 OWL 프레임워크—Odoo 웹 스택에서 프론트엔드 복잡성의 첫 번째 주요 레이어—에 초점을 맞추고, 이를 구축하는 것이 정말 필요했는지, 혹은 “ERP이니까 복잡해야 한다”는 흔히 쓰이는 변명으로 정당화될 수 있는 장기적인 복잡성의 회피 가능한 원천이었는지에 대해 질문하고자 합니다.

배경을 설명하자면, OWL (Odoo Web Library) 은 Odoo의 프론트엔드 컴포넌트(대시보드, 백엔드 UI, 웹사이트 일부 등)를 구동하는 JavaScript 프레임워크입니다.

Odoo에 따르면, OWL은 특정 문제를 해결하기 위해 처음부터 새로 만들었다고 합니다. 그 문제는 다른 모듈이 정의한 프론트엔드 컴포넌트를 코어 파일을 수정하거나 업그레이드 시 변경 사항이 사라지는 위험 없이 서드파티 개발자가 재정의하고 확장할 수 있게 하는 것입니다.

이 목표 자체는 합리적이며—심지어는 칭찬받을 만한—것입니다. 하지만 이 필요가 완전히 새로운 프론트엔드 프레임워크를 구축해야 한다는 결론은 훨씬 더 의문스럽습니다. 동일한 목표는 이미 모든 주요 현대 프론트엔드 프레임워크(React, Vue, Angular)에서 컴포넌트 조합, 슬롯, 고차 컴포넌트, 의존성 주입, 확장 API, 스키마 기반 렌더링과 같은 잘 확립된 메커니즘을 통해 달성할 수 있습니다.

성숙한 프런트엔드 프레임워크가 Odoo에 제공했을 것들

  • 명확하고 지속적으로 진화하는 문서
    성숙한 프레임워크는 실제 사용과 기능을 면밀히 반영하여 지속적으로 업데이트되는 문서를 제공한다. 반면 Odoo의 문서는 종종 불완전하거나 오래됐으며 오해를 불러일으키는 경우가 많아, 별도의 글을 쓸 정도로 큰 문제이다.

  • 보안 대응성
    현대 프런트엔드 생태계는 보안 이슈가 발견되면 빠르게 대응하여 전체 애플리케이션 업그레이드 없이 패치를 제공한다. Odoo에서는 프런트엔드 수정이 백엔드 릴리스와 밀접하게 연결돼 있어 보안 패치를 적용하는 데 훨씬 큰 방해가 된다.

  • 방대한 생태계
    폼 빌더와 스키마 검증기부터 접근성 도구, 테스트 프레임워크, UI 컴포넌트 라이브러리까지—현대 생태계는 Odoo가 부분적으로 재구현하거나 전혀 제공하지 못하는 솔루션을 제공한다.

  • 개발자 친숙도
    오늘날 프런트엔드 개발자들은 이미 React, Vue, Angular 등에 익숙하다. OWL은 Odoo의 복잡한 백엔드 추상화 위에 개발자가 새롭게 배워야 하는 독자적인 사고 모델을 도입한다.

Source:

현재 하이브리드 스택

Odoo는 이제 OWL이 레거시 코드와 공존하는 하이브리드 프런트엔드 스택을 유지하고 있습니다. 여기에는 시스템 일부에 아직도 존재하는 여러 버전의 jQuery(2.x 및 3.x)가 포함됩니다. 이는 장기적인 유지 보수성에 대한 의문을 제기해야 합니다.

OWL을 React나 Vue와 직접 비교하기 전에, OWL이 실제로 어떻게 작동하는지 이해하는 것이 중요합니다.

OWL 작동 방식

본질적으로 OWL은 백엔드에서 전송된 XML 정의를 소비하고, 프런트엔드에서 동적으로 컴포넌트 트리를 구축합니다. 이러한 XML 뷰는 파싱되고 해석되어 JavaScript로 렌더링되는 UI 컴포넌트로 변환됩니다.

예시: 간단한 OWL 폼 정의

프런트엔드는 이 XML을 받아 OWL 런타임을 사용해 렌더링된 UI 컴포넌트로 변환합니다:

  1. XML을 파싱하여 컴포넌트 트리를 만든다.
  2. 모델 필드 메타데이터를 가져오기 위해 추가 요청을 보낸다.
  3. 필드 정의에 따라 어떤 컴포넌트를 렌더링할지 결정한다.
  4. 필요에 따라 widget 속성을 사용해 커스텀 렌더러를 선택한다.

다시 말해, OWL은 런타임 XML 인터프리터 역할을 하며 UI 동작을 동적으로 생성합니다.

OWL에 대한 냉정한 진실

OWL의 유연성은 근본적으로 새로운 아이디어에서 오는 것이 아니라 구조와 동작 결정을 런타임으로 미루는 것에서 옵니다. 이것은 독특한 것이 아니며, 맞춤형 프레임워크를 필요로 하지도 않습니다.

같은 수준의 유연성은 예를 들어 React에서 다음과 같은 방법으로 구현할 수 있습니다:

  • 스키마 기반 렌더링
  • 플러그인 레지스트리
  • 선언적 확장 포인트
  • 의존성 주입을 통한 제어된 오버라이드
  • 권한이 부여된 컴포넌트 교체

많은 시스템이 이미 XML, JSON, 혹은 DSL을 파싱하고 이를 성숙한 프레임워크 내에서 안전하게 렌더링하고 있습니다 — 렌더링 라이프사이클, 상태 관리, 반응성, 도구 체계를 새롭게 발명할 필요 없이 말이죠.

OWL을 구축하기로 선택함으로써 Odoo는 다음과 같은 부담을 감수했습니다:

  • 독점 프레임워크 유지 관리
  • 이미 다른 곳에 존재하는 도구 체계 재구축
  • 프런트엔드 지식의 파편화
  • 백엔드 아키텍처 제약에 프런트엔드 진화가 결합됨

후속 섹션에서는 Odoo의 XML 기반 UI 모델을 React를 사용해 깔끔하게 렌더링하고 오버라이드하는 방법을 시연할 예정이며, 맞춤형 프레임워크 없이도 동일한 확장성을 달성할 수 있음을 보여줄 것입니다. 목표는 OWL이 사용 불가능하다고 주장하는 것이 아니라, 그것을 만들기가 새로운 문제를 해결하지 못하고 장기적인 비용을 증가시키는 불필요한 아키텍처 선택이었다는 점을 강조하는 것입니다.

간단한 OWL 컴포넌트 vs. React 컴포넌트

OWL 컴포넌트 (단순화)

/** @odoo-module **/

import { Component, xml } from "@odoo/owl";

export class Hello extends Component {
  static template = xml`
    
      

안녕하세요

`; }


Usage is typically tied to XML view definitions sent from the backend, and the component lifecycle, state handling, and rendering behavior are governed by OWL’s custom runtime.

### React 컴포넌트 (동등)

```javascript
function Hello({ name }) {
  return (
    
      

Hello {name}

); }


표면적으로 볼 때, 두 컴포넌트 모두 사소합니다. 핵심 차이는 문법이 아니라 **생태계 중력**입니다.

React에서:

- 컴포넌트 구성은 표준입니다.  
- 툴링(린팅, 테스트, 프로파일링)이 성숙했습니다.  
- 상태, 효과, 그리고 에러 경계가 명확하게 정의되어 있습니다.  
- 스키마 기반 렌더링과의 통합이 일반적입니다.

OWL은 이러한 모든 기능을 재구현하거나 근사화해야 합니다.

> **Source:**  

## React Pseudo‑Implementation That Mirrors OWL Overrides  

OWL이 제공한다는 흔한 방어 논리 중 하나는 *런타임 UI 오버라이드*—모듈이 핵심 코드를 수정하지 않고도 UI 동작을 동적으로 교체하거나 확장할 수 있다는 점이다.  

이는 **OWL에만 국한된 것이 아니다**.

아래는 동일한 기능을 구현한 **React 기반 아키텍처**의 간소화된 예시이다.

### Component Registry (Core)

```javascript
const ComponentRegistry = new Map();

export function registerComponent(name, component) {
  ComponentRegistry.set(name, component);
}

export function getComponent(name) {
  return ComponentRegistry.get(name);
}

Schema‑Driven Renderer

function Renderer({ schema }) {
  return schema.map((node) => {
    const Component = getComponent(node.type);
    return <Component key={node.id} {...node.props} />;
  });
}

Default Registration (Core Module)

registerComponent("field:text", TextField);
registerComponent("field:number", NumberField);

Override by Add‑on / Third‑Party Module

registerComponent("field:text", CustomTextField);

핵심 파일을 수정하지 않는다. 포크하지 않는다. 복잡한 UI 프레임워크가 필요하고 생태계·툴링·문서가 없는 ERP를 정당화하기 위해 프레임워크를 재빌드하지 않는다.

이와 같은 간단한 구조를 사용하면 최소한 OWL.js에서 할 수 있는 거의 모든 일을 달성하면서 기존 생태계의 훌륭한 툴링을 활용할 수 있다.

핵심 장점

  • 런타임 교체
  • 제어된 확장 포인트
  • 명확한 오버라이드 소유권
  • 예측 가능한 동작

같은 패턴은 다음에도 확장될 수 있다:

  • 권한 관리
  • 기능 플래그
  • 사용자별 오버라이드
  • 컨텍스트 기반 렌더링
  • 메뉴와 UI 번역을 처리하는 더 나은 구현

이는 본질적으로 OWL이 하는 일과 동일하지만, OWL은 이를 커스텀 렌더링 엔진, 라이프사이클 모델, 툴링 스택과 함께 번들링한다.

“하지만 React는 런타임 UI 오버라이드를 할 수 없습니다”

이것이 가장 흔한 반론이며, 오해에 기반하고 있습니다.

React는 런타임 UI 오버라이드를 완전히 지원합니다.

React가 지원하지 않는 것은 암묵적이고 구조화되지 않은 변형이며, 이는 제한이 아니라 기능입니다.

React에서 런타임 오버라이드는 다음을 통해 구현됩니다:

  • 레지스트리
  • 컨텍스트 제공자
  • 의존성 주입 패턴
  • 플러그인 시스템
  • 스키마 기반 렌더링

이 모든 방법은:

  • 명시적이며
  • 추적 가능하고
  • 테스트 가능하며
  • 도구 친화적입니다

OWL의 접근 방식은 XML의 런타임 해석과 암묵적인 동작 해결에 크게 의존합니다. 이는 유연성을 제공하지만 다음과 같은 비용이 따릅니다:

  • 디버깅 어려움
  • 정적 분석 제한
  • 예측 가능한 실패 모드 부족

React 생태계는 제한 없는 변형보다 제어된 확장성을 선호합니다. 이는 특히 여러 팀과 서드파티 개발자가 참여하는 대규모 시스템에서 시간이 지나도 유지 보수가 용이하도록 합니다.

다시 말해:

  • OWL은 최대한의 런타임 자유를 최적화합니다
  • React는 지속 가능한 확장성을 최적화합니다

마무리 설명

여기서 주장하는 바는 OWL이 사용할 수 없다는 것이 아니라, Odoo 개발자들이 기존 프레임워크를 인식하지 못한다는 것이 아닙니다.

주장은 OWL이 해결하려는 문제가 이미 해결되어 있었다는 것이며, 이를 다시 해결하기 위해 프레임워크를 재구축함으로써 근본적인 새로운 기능을 도입하지 않고 장기적인 비용만 증가시켰다는 것입니다.

Odoo는 단순히 유연성을 선택한 것이 아니라 전체 프런트엔드 스택을 자체적으로 보유하기로 선택했습니다. 스택을 보유한다는 것은 그와 함께 오는 모든 제한, 버그, 보안 문제 및 생태계 격차를 모두 책임진다는 의미입니다.

그것이 웹 스택을 재발명하는 데 드는 실제 비용입니다. 이는 Odoo가 사용할 수 없게 만드는 것은 아니지만, 장기적인 진화에 필요한 것보다 훨씬 더 큰 비용을 초래합니다.

Back to Blog

관련 글

더 보기 »

React 앱의 기본

소개 오늘은 React 앱을 생성할 때 보이는 파일과 폴더의 이유와 사용 방법을 살펴보겠습니다. !React app structurehttps:/...