Kiến trúc phân lớp (Layered Architecture)

← Về MOC · Liên quan: Môi trường đích (Target Environments)

1. Ý tưởng cốt lõi

Theo wiki Source Code Organization: VS Code gồm một core (lõi) được chia lớp và mô-đun hóa, và có thể mở rộng bằng extension. Extension chạy trong một tiến trình riêng gọi là extension host (xem Extension Host & RPC).

Core nằm ở src/vs/ và được chia thành các layer (lớp) có thứ tự. Quy tắc vàng: mỗi lớp chỉ được import từ các lớp nằm BÊN DƯỚI nó.

flowchart BT
  base["1. base<br/>tiện ích chung, UI cơ bản"]
  platform["2. platform<br/>DI + service dùng chung"]
  editor["3. editor<br/>Monaco Editor core"]
  workbench["4. workbench<br/>toàn bộ giao diện VS Code"]
  code["5. code<br/>entry desktop (Electron)"]
  server["6. server<br/>entry remote server"]
  sessions["7. sessions<br/>Agents Window"]
  base --> platform --> editor --> workbench --> sessions
  platform --> code
  platform --> server

2. Chi tiết từng lớp

2.1 base – nền tảng

  • Tiện ích tổng quát và khối UI cơ bản, không phụ thuộc service nào.
  • Ví dụ: base/common/strings.ts, arrays.ts, async.ts, event.ts (sự kiện), lifecycle.ts (Disposable), observable.ts, uri.ts; base/browser/ui/ (list, tree, scrollbar…).
  • Xem cơ chế quan trọng: Disposable & Event, Observables (lập trình phản ứng).

2.2 platform – dịch vụ nền

  • Định nghĩa cơ chế service injection (tiêm dịch vụ) và các service cơ bản dùng chung giữa workbench và code.
  • Không được chứa code riêng của editor hay workbench.
  • Ví dụ thư mục: platform/instantiation (DI), platform/files (đọc/ghi file), platform/configuration (cài đặt), platform/storage, platform/log, platform/commands, platform/contextkey, platform/keybinding, platform/registry…
  • Xem: Dependency Injection & Services.

2.3 editor – Monaco Editor core

  • Là lõi trình soạn thảo văn bản, không được phụ thuộc node hay electron-* để có thể chạy trên web.
  • Bản Monaco Editor đầy đủ (gói npm dùng trong web app khác) được đóng gói ở repo riêng microsoft/monaco-editor.
  • Cấu trúc con:
    • editor/common, editor/browser: phần lõi không thể thiếu.
    • editor/contrib: 59 tính năng editor (find, folding, suggest, hover, multicursor, stickyScroll…), dùng chung cho VS Code và standalone editor.
    • editor/standalone: chỉ dành cho bản standalone; không ai được phụ thuộc vào thư mục này.
    • Tính năng editor chỉ có trong VS Code thì đặt ở workbench/contrib/codeEditor.

2.4 workbench – bàn làm việc

  • Chứa Monaco Editor, notebook, custom editor và khung giao diện gồm Explorer, Status Bar, Menu Bar…
  • Dùng Electron cho bản desktop, dùng browser API cho bản web.
  • Cấu trúc con:
Thư mụcVai trò
workbench/{common,browser,electron-browser}Lõi workbench, càng tối giản càng tốt (layout, parts)
workbench/browser/parts/Các “part” giao diện: activitybar, sidebar, editor, panel, statusbar, titlebar, auxiliarybar…
workbench/services/Service lõi của workbench (95 nhóm) – không chứa service chỉ dùng trong một contrib
workbench/contrib/Feature contribution (tính năng đóng góp): search, debug, git/scm, terminal, chat… (101 nhóm). Phần lớn code mới nên nằm ở đây
workbench/api/Hiện thực Extension API (vscode.d.ts) – cả phía extension host và phía workbench

2.5 code – điểm vào desktop

  • “Khâu nối” mọi thứ cho ứng dụng desktop: file main của Electron, shared process, CLI.
  • Ví dụ: code/electron-main/main.ts, code/electron-main/app.ts. Xem Luồng khởi động (Startup flow).

2.6 server – điểm vào server từ xa

  • Dùng cho Remote Development (SSH, Container, WSL, Codespaces): phần server chạy ở máy từ xa.

2.7 sessions – Agents Window (lớp mới)

  • Cửa sổ dành cho quy trình làm việc với AI agent. Được import từ workbench trở xuống, nhưng workbench không bao giờ được import từ sessions.
  • Xem: Agents Window & AI trong repo.

3. Cơ chế bảo vệ quy tắc phân lớp

Quy tắc không chỉ nằm trên giấy, mà được kiểm tra tự động:

Công cụVị tríTác dụng
ESLint rule local/code-layering.eslint-plugin-local/code-layering.tsBáo lỗi khi import sai lớp/môi trường
ESLint rule local/code-import-patterns.eslint-plugin-local/code-import-patterns.tsQuy định mẫu import được phép theo từng thư mục
npm run valid-layers-checkbuild/checker/layersChecker.tsKiểm tra phân lớp ở mức toàn dự án

Ví dụ vi phạm (minh họa)

// File: src/vs/base/common/myUtil.ts   (lớp base)
// ❌ SAI: base không được import từ platform (lớp cao hơn)
import { IFileService } from '../../platform/files/common/files.js';
 
// File: src/vs/workbench/contrib/myFeature/browser/myFeature.ts
// ✅ ĐÚNG: workbench được import từ platform và base
import { IFileService } from '../../../../platform/files/common/files.js';
import { URI } from '../../../../base/common/uri.js';

Vì sao import có đuôi .js dù file là .ts?

Code được biên dịch sang ESM (ECMAScript Modules – chuẩn module của JavaScript). Trong ESM, đường dẫn import phải trỏ đúng file sau biên dịch (.js). TypeScript hiểu và ánh xạ ngược về file .ts.

4. Vì sao phải phân lớp?

  1. Tái sử dụng: lớp editor chạy độc lập được → tách ra thành Monaco Editor dùng trên web.
  2. Đa nền tảng: tách code phụ thuộc Node/Electron giúp cùng một code chạy cả desktop lẫn web.
  3. Dễ bảo trì: tránh phụ thuộc vòng (cyclic dependency). Repo còn có lệnh npm run check-cyclic-dependencies.

Liên kết