清洁架构:遥不可及的理想——给开发者的寓言

清洁架构:遥不可及的理想——给开发者的寓言

在西藏宁静的山区高处,一座古老寺院安静的大厅里,住着一位年轻的学徒。他致力于追求和谐——不仅在他自己内部,而且在他的编程技巧中。他的目标是创建一个完美的应用程序,一个能够体现清洁架构深刻原理的应用程序,就像山间溪流的清澈一样。但他意识到这条道路的艰辛,于是向一位可敬的明师寻求智慧。

徒弟谦卑地走近师父问道

—“噢,明智的师父,我已经构建了一个应用程序来管理购买。我的建筑干净纯粹吗?”

师父耐心地观察弟子,回答道:

—“向我展示你所创造的东西,我们将一起辨别真相。”

学徒展示了他的作品,其中数据库逻辑和用例流程交织在一起——业务逻辑与技术框架紧密地交织在一起,就像一张错综复杂的网中的线。

// app.tsimport sqlite3 from 'sqlite3';import { open, database } from 'sqlite';interface purchase {    id: number;    title: string;    cost: number;}async function initializedatabase(): promise {    const db = await open({        filename: ':memory:',        driver: sqlite3.database,    });    await db.exec(`    create table purchases (      id integer primary key,      title text,      cost real    )  `);    return db;}async function addpurchaseifcan(db: database, purchase: purchase): promise {    const { id, title, cost } = purchase;    const row = await db.get(        `select sum(cost) as totalcost from purchases where title = ?`,        [title]    );    const totalcost = row?.totalcost || 0;    const newtotalcost = totalcost + cost;    if (newtotalcost  {    const db = await initializedatabase();    await addpurchaseifcan(db, { id: 3, title: 'rice', cost: 2 });})();

大师思考代码后说道:

——“你的代码就像一条河流,目的的清水与实现的泥浆混合在一起。业务和技术问题本应分开进行,但它们已合而为一。为了在你的建筑中实现真正的纯粹,你必须将它们分开,就像天空与大地分开一样。”

道路上的第一步

听从师父的话,徒弟开始着手重构他的代码。他开始分离各层,在数据库和业务逻辑流之间划出明显的界限。他还引入了接口,使他的代码与依赖倒置原则保持一致,这是清洁架构的神圣教义之一。现在,他的应用不再依赖于具体的实现,而是依赖于思想的抽象。

// app.tsimport { initializedatabase } from './db/init';import { purchaserepository } from './db/purchaserepository';import { addpurchaseifcan } from './usecases/addpurchaseifcan';(async () => {  const db = await initializedatabase();  const purchaserepository = new purchaserepository(db);  await addpurchaseifcan(purchaserepository, { id: 3, title: 'rice', cost: 2 });})();
// usecases/addpurchaseifcan.tsimport { ipurchaserepository, purchase } from './ipurchaserepository';export async function addpurchaseifcan(  purchaserepository: ipurchaserepository,  purchase: purchase): promise {  const { id, title, cost } = purchase;  const totalcost = await purchaserepository.gettotalcostbytitle(title);  const newtotalcost = totalcost + cost;  if (newtotalcost < 99999) {    await purchaserepository.add(purchase);    console.log('purchase added successfully.');  } else {    console.log('total cost exceeds 99999.');  }}
// usecases/ipurchaserepository.tsexport interface ipurchaserepository {  add(purchase: purchase): promise;  gettotalcostbytitle(title: string): promise;}export interface purchase {  id: number;  title: string;  cost: number;}
// db/init.tsimport sqlite3 from 'sqlite3';import { open, database } from 'sqlite';export async function initializedatabase(): promise {  const db = await open({    filename: ':memory:',    driver: sqlite3.database,  });  await db.exec(`    create table purchases (      id integer primary key,      title text,      cost real    )  `);  return db;}
// db/purchaserepository.tsimport { database } from 'sqlite';import { ipurchaserepository, purchase } from 'usecases/ipurchaserepository';export class purchaserepository implements ipurchaserepository {  private db: database;  constructor(db: database) {    this.db = db;  }  async add(purchase: purchase): promise {    const { id, title, cost } = purchase;    await this.db.run(      `insert into purchases (id, title, cost) values (?, ?, ?)`,      [id, title, cost]    );    return purchase;  }  async gettotalcostbytitle(title: string): promise {    const row = await this.db.get(      `select sum(cost) as totalcost from purchases where title = ?`,      [title]    );    const totalcost = row?.totalcost || 0;    return totalcost;  }}

徒弟回到师傅并问道:

——“我已经为我的存储库分离了各层并使用了接口。我的建筑现在干净了吗?”

大师再次检查代码,回复:

——“你们已经向前迈出了一步,但总成本的计算仍然停留在基础设施上,它不属于那里。这不是这种智慧应该存在的地方。总成本的知识属于商业领域,而不是地球上的工具。将其移至用例中,过程的智慧可以保持其纯粹性。”

分离的教训

有了这种洞察力,学徒意识到总成本的计算是业务逻辑的一部分。他再次重构了代码,将逻辑转移到用例中,使业务问题不受技术基础设施的影响。

// usecases/ipurchaserepository.tsexport interface ipurchaserepository {  add(purchase: purchase): promise;-  gettotalcostbytitle(title: string): promise;+  getpurchasesbytitle(title: string): promise;}...
// usecases/addpurchaseifcan.tsimport { ipurchaserepository, purchase } from './ipurchaserepository';export async function addpurchaseifcan(  purchaserepository: ipurchaserepository,  purchasedata: purchase,  limit: number): promise {  const { id, title, cost } = purchasedata;  const purchases = await purchaserepository.getpurchasesbytitle(title);  let totalcost = 0;  for (const purchase of purchases) {    totalcost += purchase.cost;  }  const newtotalcost = totalcost + cost;  if (newtotalcost >= limit) {    console.log(`total cost exceeds ${limit}.`);  } else {    await purchaserepository.add(purchasedata);    console.log('purchase added successfully.');  }}
// db/purchaserepository.tsimport { database } from 'sqlite';import { ipurchaserepository } from './ipurchaserepository';export class purchaserepository implements ipurchaserepository {  ...  async getpurchasesbytitle(title: string): promise {    const rows = await this.db.all(      `select * from purchases where title = ?`,      [title]    );    return rows.map((row) => ({      id: row.id,      title: row.title,      cost: row.cost,    }));  }}

再次回到师父身边,问道:

—“我已将总成本计算转移到用例中,并将业务逻辑与基础设施分开。我的建筑现在纯净了吗?”

师父带着温柔的微笑回答:

——“你已经取得了很大的进步,但要小心——就像山风带来冬天的寒冷一样,你的计算可能会带来隐藏的错误。 javascript 的算术就像新手的思维一样,在处理大数或小数时可能会不精确。”

与无常的相遇

学徒明白javascript中浮点运算的缺陷可能会导致微妙但危险的错误。他修改了代码,转向更可靠的工具,一个专为精确计算而设计的库,寻求工作的清晰度。

// usecases/addpurchaseifcan.ts+ import decimal from 'decimal.js';import { ipurchaserepository, purchase } from './ipurchaserepository';export async function addpurchaseifcan(  purchaserepository: ipurchaserepository,  purchasedata: purchase,  limit: number): promise {  const { id, title, cost } = purchasedata;  const purchases = await purchaserepository.getpurchasesbytitle(title);  let totalcost = new decimal(0);  for (const purchase of purchases) {-    totalcost += purchase.cost;+    totalcost = totalcost.plus(purchase.cost);  }- const newtotalcost = totalcost + cost;+ const newtotalcost = totalcost.plus(cost);- if (newtotalcost >= limit) {+ if (newtotalcost.greaterthanorequalto(limit)) {    console.log(`total cost exceeds ${limit}.`);  } else {    await purchaserepository.add(purchasedata);    console.log('purchase added successfully.');  }}

他再次问师父:

—“我已经改进了我的计算,使用了更好的工具来避免错误。我的建筑现在达到纯粹了吗?”

上人目光坚定如山,答道:

——“你做得很好,但你的架构仍然受到束缚。您的业​​务逻辑现在取决于这个新工具decimal.js的详细信息。如果有一天你需要改变这个工具,你的逻辑基础就会动摇。真正的纯洁是摆脱这种束缚。”

依赖倒置的智慧

认识到大师话语的深度,学徒试图将他的代码从这种执着中解放出来。他抽象了算术运算,颠倒了依赖关系,这样他的业务逻辑就不再依赖于任何一种工具。

// usecases/calculator.tsexport abstract class calculator {  abstract create(a: number): calculator;  abstract add(b: calculator | number): calculator;  abstract greaterthanorequal(b: calculator | number): boolean;}
// usecases/addpurchaseifcan.ts+ import { calculator } from 'usecases/calculator';- import decimal from 'decimal.js';import { ipurchaserepository, purchase } from './ipurchaserepository';
// decimalcalculator.tsimport decimal from 'decimal.js';import { calculator } from 'usecases/calculator.ts';export class decimalcalculator extends calculator {  private value: decimal;  constructor(value: number | decimal) {    super();    this.value = new decimal(value);  }  create(a: number): calculator {    return new decimalcalculator(a);  }  add(b: calculator | number): calculator {    return new decimalcalculator(this.value.plus(b.value));  }  greaterthanorequal(b: calculator | number): boolean {    return this.value.greaterthanorequalto(b.value);  }}
// useCases/addPurchaseIfCan.tsimport { Calculator } from 'useCases/calculator';import { IPurchaseRepository, Purchase } from './IPurchaseRepository';export class addPurchaseIfCan {  private purchaseRepository: IPurchaseRepository;  private calculator: Calculator;  private limit: string;  constructor(    purchaseRepository: IPurchaseRepository,    calculator: Calculator,    limit: number  ) {    this.purchaseRepository = purchaseRepository;    this.calculator = calculator;    this.limit = limit.toString();  }  async execute(purchaseData: Purchase): Promise {    const { id, title, cost } = purchaseData;    const purchases = await this.purchaseRepository.getPurchasesByTitle(title);    let totalCost = this.calculator.create(0);    for (const purchase of purchases) {      totalCost.add(purchase.cost);    }    totalCost = totalCost.add(cost);    if (totalCost.greaterThanOrEqual(this.limit)) {      console.log(`Total cost exceeds ${limit}.`);    } else {      await this.purchaseRepository.add({        id,        title,        cost: parseFloat(cost.toString()),      });      console.log('Purchase added successfully.');    }  }}

最后一次回到师父身边,他问道:

——“我使用依赖倒置抽象了我的操作,确保我的业务逻辑不再与实现绑定。我的建筑现在真的干净了吗?”

师父开示:

——“这条路上你已经走得很远了。但请记住,即使您努力追求纯度,您的用例仍然取决于编写它们的语言。您现在使用的是 javascripttypescript,但有一天这些工具可能会消失。当那一天到来时,你会用新的语言重建一切吗?”

拥抱不完美

学徒对此感到困惑,问道:

——“大师,如果我的用例总是与编写它们的语言联系在一起,我怎样才能在我的架构中实现完美的整洁?”

师父带着理解的柔和微笑回答:

——“就像鸟儿无法离开天空一样,建筑也不能完全脱离其创作的工具。真正的独立是一个崇高的梦想,但却是遥不可及的。然而,对它的追求会给你的建筑带来和谐。 清洁架构的目标不是摆脱所有依赖性,而是创建一个轻松应对变化的系统,并将商业智慧与地球运作分开。理解这种平衡是获得真正智慧的关键。”

学徒,感受到他内心的理解黎明之光,说道:

——“谢谢师父。现在我发现完美不是孤立的,而是责任和目标的和谐。”

师父从座位上站起来,回答:

——“放心吧,学徒。你的旅程才刚刚开始,但你已经找到了自己的路。”

结语

随着时间的流逝,学徒注意到他的应用程序开始变慢。他很困惑,想知道一个曾经运行得如此顺利的系统现在如何在执行任务时陷入困境。

很明显,问题不在于代码的大小不断增长,而在于总成本计算是在数据库外部进行的。该应用程序花费了大量的精力来传输大量数据,只是为了执行本可以在源头完成的任务。如果计算是在数据库内完成的,则无需在层之间发送数千条记录,并且性能仍将保持强劲。

徒弟想向师父询问此事,但师父已经消失,问题一直没有答案。

望着寂静的寺院,徒弟拿起一本新书,微笑着说道:

—“看来我的启蒙之路给我带来了新的挑战 – 性能优化的艺术。”

以上就是清洁架构:遥不可及的理想——给开发者的寓言的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1493240.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Shadcn CLI如何使用错误常量来提高代码可读性
上一篇 2025年12月19日 15:31:36
清晰函数名称的力量:干净的代码必不可少
下一篇 2025年12月19日 15:31:40

相关推荐

  • mac怎么合并多个PDF文件_Mac合并PDF文件方法

    使用macOS可便捷合并PDF:1. 用预览拖拽缩略图或插入文件;2. 通过访达快速操作批量合并;3. 借助在线工具如iLovePDF处理。 如果您需要将多个PDF文件整合为一个文档以便于分享或管理,macOS系统提供了多种便捷的合并方式。以下是一些有效的操作步骤: 本文运行环境:MacBook P…

    2026年9月20日
    000
  • 怎样在VSCode中查看Git提交历史?

    VSCode通过内置源代码管理视图查看Git提交历史,点击左侧图标或使用快捷键Ctrl+Shift+G进入;2. 在COMMIT输入框下方点击“…”菜单选择View Commit History可查看完整提交记录;3. 右键文件选择Git: View File History可查看单个文…

    2026年9月20日
    100
  • 怎样在VSCode中比较两个文件的差异?

    VSCode内置文件比较功能可通过命令面板或资源管理器右键菜单启动,操作简便无需插件;2. 使用“Compare Active File With…”或“Select for Compare”后选择文件即可并排查看差异;3. 差异显示中绿色为新增、红色为删除内容,支持逐项浏览与导航,适用…

    2026年9月20日
    000
  • VSCode怎么查看NPM版本_VSCode NPM版本查询教程

    在VSCode中查看NPM版本,需打开集成终端并输入npm -v或npm –version。1. 使用快捷键Ctrl + (Windows/Linux)或Cmd + (macOS)打开终端;2. 输入命令npm -v执行;3. 终端将显示当前NPM版本号,如8.19.2。该方法可快速验证…

    2026年9月20日
    000
  • MAC Sonoma系统的新功能台前调度怎么用_MAC Sonoma台前调度使用方法

    台前调度可自动整理Mac窗口,提升多任务效率。通过系统设置或控制中心开启功能,支持快捷键设置(如Command+1)快速切换,能将Safari与备忘录等应用拖拽分组管理,并自定义显示最近使用App、桌面访问方式及窗口展示模式,优化工作流。 如果您在使用Mac时感到桌面窗口杂乱,难以高效管理多个应用程…

    2026年9月20日
    300
  • mac怎么重建Spotlight索引_Mac重建Spotlight索引方法

    重建Spotlight索引可解决搜索结果不准确问题。方法一:通过系统设置将启动磁盘添加后移除隐私列表,触发重新索引;方法二:使用终端命令“sudo mdutil -E /”强制重建索引;方法三:重启进入安全模式,系统自动修复并清理索引,适用于前两种方法无效时。 如果您发现Mac上的Spotlight…

    2026年9月20日
    000
  • 怎样在VSCode中为不同文件类型设置不同的缩进?

    在VSCode中可为不同文件类型设置缩进,通过settings.json按语言ID配置,如Python用4空格、HTML用2空格,保存后自动生效并覆盖全局设置。 在 VSCode 中为不同文件类型设置不同的缩进,可以通过配置语言特定的设置来实现。VSCode 支持按语言 ID 覆盖编辑器的缩进行为,…

    2026年9月20日
    100
  • VSCode怎么把代码整齐_VSCode代码格式化与自动排版功能设置教程

    VSCode代码格式化可显著提升代码可读性与质量,通过内置功能及Prettier、ESLint插件实现。安装Prettier和ESLint插件后,需在设置中配置默认格式化工具、保存时自动格式化(Format On Save)、粘贴时格式化(Format On Paste)及保存时修复ESLint问题…

    2026年9月20日
    100
  • 怎样在VSCode中重命名变量或文件?

    使用F2键可快速重命名变量或文件,VSCode会自动更新符号引用,支持多语言,重命名文件时需注意导入路径可能需手动调整。 在 VSCode 中重命名变量或文件非常方便,可以通过内置的重构功能快速完成,同时保持代码的一致性。 重命名变量(符号重命名) 当你想重命名代码中的变量、函数或类时,VSCode…

    2026年9月20日
    000
  • 如何使用VSCode的源代码管理视图?

    VSCode的SCM视图可高效管理Git工作流。1. 点击左侧源代码管理图标或使用快捷键Ctrl+Shift+G打开视图;2. 查看未暂存和已暂存更改,通过点击“+”号暂存文件;3. 输入提交信息后按Ctrl+Enter提交,点击同步按钮推送至远程仓库;4. 通过状态栏分支名称切换或创建分支,冲突时…

    2026年9月20日
    000
  • 怎样在VSCode中快速跳转到函数定义?

    使用F12或Ctrl+点击跳转到函数定义,Ctrl+F12预览定义,需安装语言扩展并配置项目文件以确保功能正常。 在 VSCode 中快速跳转到函数定义,主要依赖编辑器的智能感知和语言服务器功能。只要项目环境配置正确,操作非常高效。 使用“转到定义”功能 这是最常用的方法,适用于大多数编程语言: 将…

    2026年9月20日
    100
  • VSCode的调试控制台有哪些高级用法?

    调试控制台是VSCode中强大的交互式环境,支持运行表达式、修改变量、调用函数和使用console API。1. 可执行JS/TS表达式查看变量、调用方法或计算逻辑;2. 能动态修改变量值以测试不同场景;3. 支持调用已定义函数验证行为;4. 可用console.table、group、trace等…

    2026年9月20日
    100
  • MAC的快捷键大全有哪些_macOS常用高效快捷键汇总

    掌握Mac键盘快捷键可显著提升操作效率。①系统级:Command+空格打开聚焦搜索,Control+Command+Q锁定屏幕,Command+Tab切换应用,Option+Command+Esc强制退出程序。②窗口管理:Command+M最小化窗口,Command+H隐藏当前应用,Command+…

    2026年9月20日
    200
  • 如何配置VSCode的自动保存功能?

    开启VSCode自动保存可提升效率,通过设置“Files: Auto Save”选择off、afterDelay、onFocusChange或onWindowChange模式,并可为afterDelay设置毫秒级延迟时间,配置即时生效。 VSCode 的自动保存功能可以帮助你避免手动频繁保存文件。开…

    2026年9月20日
    300
  • 怎样利用VSCode的历史记录对比两个不同Git提交之间的文件差异?

    首先使用VSCode命令面板选择一个提交,再通过“Compare with”功能对比另一提交或工作区版本;结合GitLens可直接选取两个任意提交,查看文件差异。 在VSCode中对比两个不同Git提交之间的文件差异,可以通过内置的Git功能结合命令面板操作来实现。虽然VSCode没有直接提供“选择…

    2026年9月20日
    100
  • 如何在Laravel中管理静态资源

    在laravel中管理静态资源的核心方法是使用public目录结合vite或laravel mix等构建工具实现高效加载和版本控制。1. public目录作为所有公开访问资源的根目录,由web服务器直接提供服务;2. 使用asset()、vite()或mix()辅助函数生成带版本哈希的url,确保浏…

    2026年9月13日
    100
  • VSCode写HTML怎么写_VSCode编写HTML代码的基础与高效技巧教程

    VSCode写HTML怎么写_VSCode编写HTML代码的基础与高效技巧教程VSCode写HTML怎么写_VSCode编写HTML代码的基础与高效技巧教程VSCode写HTML怎么写_VSCode编写HTML代码的基础与高效技巧教程VSCode写HTML怎么写_VSCode编写HTML代码的基础与高效技巧教程

    VSCode写HTML的核心在于利用其高效工具与扩展提升开发效率。首先,保存文件为.html后,语法高亮与Emmet自动补全即刻生效,输入!+Tab可生成HTML5骨架,div、p等标签输入后按Tab即可扩展为完整标签对。Emmet支持复杂缩写如div.container>ul>li*3…

    2026年9月13日 用户投稿
    200
  • 如何清理VSCode的缓存?

    清理 VSCode 缓存可解决启动慢、插件异常等问题。1. 删除用户数据缓存:Windows 删除 C:Users用户名AppDataRoamingCode,macOS 删除 ~/Library/Application Support/Code,Linux 删除 ~/.config/Code;2. …

    2026年9月13日
    000
  • VSCode的括号着色功能有什么用?

    括号着色通过为不同层级的括号赋予颜色,帮助开发者快速识别匹配关系,减少语法错误。在VSCode中,该功能支持多种语言,可通过设置开启“Editor: Bracket Pair Colorization”,并自定义配色方案,提升代码可读性和编写效率。 vscode的括号着色功能主要是为了帮助开发者更轻…

    用户投稿 2026年9月13日
    400
  • 《巫师3》十周年!《巫师交响音乐会》登陆上海

    CD PROJEKT RED 今日正式揭晓,《巫师3:狂猎》十周年特别企划——《巫师交响音乐会》全球巡演即将开启亚洲篇章。本次巡演将陆续登陆上海、首尔、马尼拉等多个亚洲重要城市,更多演出地点也将逐步公布。其中,上海站将采用百人规模的大型交响乐团阵容,带来震撼人心的视听盛宴,令人翘首以待! 这场专为纪…

    2026年9月13日
    000

发表回复

登录后才能评论
关注微信