
从本地工厂到 Global:一次技术质疑的应对
Smart Quotation (SQ) ,一个公司内部的报价系统。它不是面向互联网用户的产品,是在公司内部流程里承接报价、项目、主数据、计算这些事情。这个系统一开始不是为 global 场景设计的。
它最早只是给 local 本地工厂使用。后来 global 团队发现,这套系统在其他区域也有复用价值。前面的业务讨论大部分都已经推进得差不多了,大家要确认的是:这套中国已经跑成熟的系统,能不能作为 global 方案继续往前走。
事情卡住的地方,反而不是业务流程。
德国中央总部有一位并不直接负责技术的同事看完之后,粗糙的评论了一句:C# 这个语言太老了,这个系统技术不行。
这句话表面上是技术判断,背后其实还有组织选择。总部其实更倾向自己重新开发一套系统,而不是采购中国这边已经成熟运行的 SQ。这个想法本身可以讨论,重新开发也不是绝对不行。但我们作为技术方,不能接受用“C# 太老”“技术不行”这种很粗的理由,把一个已经稳定运行的系统直接否定掉。
所以后面才有了那场会议。我们希望把相关业务和技术专家都拉进来,把系统架构、技术栈、安全评估、运行数据、业务功能和未来演进讲清楚。不是为了吵架,而是为了证明一件事:如果总部不想采用这套系统,请给出真实的业务或组织理由,不要把问题包装成一个站不住脚的技术结论。
在准备会议之前,我们反复打磨 PPT,也找了中国这边很多架构专家一起 review。大家讨论的重点不是怎么把话说得更强硬,而是怎么把证据摆完整。
在最初的沟通里,对方一开始问过这个系统是什么框架开发的,有没有用 Angular。
我当时准备的回答很直接:
Smart Quotation is developed using ASP.NET Core for the backend,
with a combination of Vue.js and Razor (.cshtml) for the frontend.
The application does not use Angular.这句话本身没错。后端是 ASP.NET Core,前端是 Vue.js 加 Razor 视图,系统没有使用 Angular。
引发后续准备的,是那句回复:“C# 太老了”。
如果是在闲聊,我可能会立刻反驳:“ASP.NET Core 不等于旧的 .NET Framework。” 但真实工作里,尤其是跨国家、跨语言、跨团队的沟通,这种反驳很容易变成一句情绪化的防守。对方说“太老”,他可能在说技术选型不符合他的认知,也可能在担心后续维护,也可能只是把 ASP.NET Core、Razor、Angular 这些东西混在了一起。
我需要处理的不是一句评价,而是这句话后面可能带来的结论。
如果“太老”被写进会议判断,后面就可能变成系统不适合 global rollout、总部需要另起炉灶、已有系统只能停留在 local 范围。到那个时候,再解释“其实不是这样”就很被动了。
所以我后来准备的 PPT,没有把主题写成“为什么 ASP.NET Core 不老”。我把它改成了架构说明。
我想把讨论从一句技术偏好,拉回到一个系统到底能不能继续支撑业务。
没有先 defend 技术栈
刚开始我确实很想证明这套技术没有问题。
ASP.NET Core 还在持续演进。Vue.js 是常见前端框架。Razor 在企业内部系统里也并不稀奇。没有使用 Angular,也不等于架构落后。
这些话都可以说,但如果只说这些,还是在围绕“新不新”打转。
后来我把准备方向改成了三块:
| PPT 里的部分 | 我想回答的问题 |
|---|---|
| Network Architecture | 这个系统部署和通信链路有没有架构瓶颈 |
| Application Technology Architecture | 当前技术栈是什么,未来准备怎么演进 |
| Security Relevance Assessment | 安全、权限、证书、部署流程有没有被评估过 |
我当时刻意用了这个顺序。
因为如果对方质疑的是一个系统,我就不能只解释一个框架。SQ 不是一组页面加几个接口。它连着公司内部身份体系,连着用户管理、主数据、项目管理、报表、计算逻辑和数据集成服务。里面还有不同角色的用户,包括管理员、业务用户、支持人员,也有外部系统连接。
PPT 里有一页 Building block view,我当时就是想用它说明系统边界。脱敏后可以这样理解:
Users:
Admin User / Domain User / Support User
Identity and access:
Company AD / OneIdM / internal identity platform
SQ modules:
User management
Master data management
Project management
Report management
Permission and role management
Business logic processing and calculation
Data integration service
External systems:
Data platform and other connected systems这页不是为了显得架构图很大。它要回答一个问题:SQ 被质疑时,我们到底在讨论哪一块?
如果只看前端框架,对方会很容易把系统想象成一个普通 Web 页面。但从 Building block view 看,它更像一个内部业务应用的组合体。身份、权限、项目状态、数据输入、公式计算、结果展示,这些东西绑在一起。你要动它,就不能只用“换一个更现代的前端框架”来描述工作量。
在这种系统里,“语言太老”这个说法太粗了。
我更希望对方回答的是:你觉得哪一层老?
是身份认证这层?是前端页面?是后端框架?是数据集成?是部署架构?还是运维模型?
这个问题问出来之后,对话就不一样了。它不再是我和对方比谁更了解某个框架,而是一起把系统分层看。
用 As-is 和 Planned to be 保护讨论边界
那份 PPT 里,我把内容分成 As-is 和 Planned to be。
这其实是我后来觉得最有用的做法。因为它避免了两个极端。
一个极端是死守现状,好像现在的系统一点问题都没有。另一个极端是把现状说得一无是处,然后直接跳到重写。
真实情况通常没那么干净。一个跑了几年的内部系统,肯定有历史痕迹,也肯定有它能继续运行的原因。
所以我需要同时说清楚两件事:
AS-IS:
The system is built around the .NET technology stack,
centered on ASP.NET Core,
with a frontend that adopts a hybrid model of Vue.js and Razor.
PLANNED TO BE:
Move toward a more decoupled frontend-backend structure.
Introduce multilingual management and system monitoring modules.
Improve scalability, maintainability and security step by step.我现在回头看,这段表达比单纯说“这个技术不老”要好。
它承认当前系统不是一个完全现代化的前后端分离项目。Vue.js 和 Razor 混用,确实需要看边界是否清楚。如果页面交互逻辑、服务端渲染和后端业务逻辑搅在一起,那问题就不叫“语言太老”,而是职责边界不清。
但它也没有把问题扩大成“必须全部重写”。我们可以先把前后端边界理清楚,把监控补起来,把多语言管理模块独立出来,把安全和可维护性逐步改善。
PPT 里还放了一个 Planned to be 的 building block。相比 As-is,它没有推翻原来的业务模块,而是在原有用户管理、主数据管理、项目管理、报表管理、计算和数据集成之外,预留了 AI Service 的位置,并且标注了和 OpenAI 相关的可能接入。
这点我现在看也很有价值。因为它说明我当时不是在说“保持不变”。我想表达的是:系统可以演进,但演进应该落在明确的位置。比如 AI 能力应该作为一个独立服务接入,而不是把现有业务模块打散之后重写。这样讲,比“我们以后也可以用 AI”要实在很多。
这才是我想表达的判断:当前技术栈不是一句“太老”就能否定的,但现状也不是不需要改。
展示真实的运行数据
准备这场沟通时,我意识到一个问题:架构讨论如果没有数据,很容易变成观点互相撞。
所以 PPT 后面放了 CPU 和内存的运行情况。
我没有想用这些图证明系统完美。它们只能说明一件事:如果有人认为 SQ 当前存在明显容量瓶颈,那至少要先看运行数据。
当时的监控结论大概是:
CPU:
8 cores.
Most of the time below 50%.
A short peak around 64%, still controllable.
Memory:
Expanded from 16GB to 32GB.
Before expansion, memory load was relatively high.
After expansion, peak usage stabilized around 50%.这些数字对沟通有用。
因为它们把“系统是不是撑不住”这个问题,从感觉拉回到证据。CPU 没有长期打满,内存扩容后负载下降,说明当前主要矛盾不一定是服务器资源不够。那如果还要说架构有风险,就要继续说清楚是哪一种风险。
也正因为有这些数据,我在 PPT 里才敢写当前网络架构没有明显扩展瓶颈。更准确地说,不是系统永远没有瓶颈,而是在当时的架构视角下,网络和部署层面没有发现会直接卡住扩展的问题。
然后我再给出未来方案:引入负载均衡,对应用服务器做水平扩展。服务保持无状态,可以让应用层扩容变得现实。数据库侧的扩展要单独评估,不能简单靠一句“无状态”带过去。
这套表达比“我们以后可以扩容”更具体。
Current:
No obvious architecture bottleneck has been identified from the network and deployment view.
Planned:
Introduce load balancing.
Scale application servers horizontally where possible.
Evaluate database scaling separately.
Rely on stateless service design to make application-layer scaling realistic.我后来发现,这类证据在跨团队沟通里很有用。因为你不能只说自己熟悉系统,你要让别人看到你是怎么判断系统的。
这里还有一个我没有在文章第一版里写清楚的点:PPT 里写了当前网络架构已经走过内部架构评审流程,并且结论是符合公司规范。这个信息对 argue 很有用。
它不是说系统从此不需要改,而是说明讨论起点不能是“这东西没人看过”。如果一个架构已经经过内部评审,再要提出推翻或大改,就要拿出新的事实:业务量变化、可用性要求变化、安全要求变化,或者维护成本已经失控。否则讨论很容易变成个人偏好。
安全评估不能只写一句 compliant
PPT 里还有一页是 Security Relevance Assessment。
这页必须讲清楚。因为德国同事在看系统时,通常不会只看功能。他们会关心系统有没有经过流程评估,权限控制是否清楚,证书怎么处理,部署是不是可控,代码有没有做检查。
如果我只说“系统是内部应用,所以安全风险不大”,这个说法很不专业。
我当时准备的思路是:把安全相关问题拆开,而不是打包成一句“没问题”。
文章里不适合放内部编号和具体人名,我只保留脱敏后的判断:
| 关注点 | 当时 PPT 里的处理方式 |
|---|---|
| 安全评估流程 | 已经过内部安全相关流程评估,所有评估项已关闭 |
| 证书和通信 | 访问服务使用加密,证书定期更新 |
| 代码规范 | 有代码规范和代码评审 |
| 软件安装和更新 | 更新动作只允许特定角色执行 |
| 配置和部署 | VM、Web Server 和部署动作使用公司标准账号与工具 |
| 静态代码分析 | 已执行,并按要求修改 |
这页的作用,不是把系统包装成没有风险。
它的作用是告诉对方:我知道安全不是一句口号。哪些项已经做了,哪些项存在豁免或业务选择,都要放在桌面上讲。
比如渗透测试这一项,PPT 里不是简单写“已完成”,而是写清楚了系统部署级别、内部应用属性,以及业务方对测试活动的选择。这种写法其实更真实。它没有把所有事情说成完美完成,而是把判断依据和当前状态摆出来。
如果对方继续 challenge,那也没关系。我们可以继续讨论某一项控制是否足够,而不是停留在“这个系统老不老”。
运维模型
还有一页我现在看也觉得有必要,就是 Operation concept。
很多技术争论都会绕到一个问题:谁来维护?
如果一个系统只有一个人懂,再新的技术也会变成风险。如果一个系统有清晰的支持边界,即使技术栈没那么时髦,也未必不能继续演进。
当时 PPT 里写了当前模型和未来模型。当前主要由产品负责人作为第一联系人,后面有本地团队支持。未来希望把支持范围扩展到更稳定的团队组合里,包括其他地区的技术团队。
我不会在博客里写具体组织细节,但这个思路可以保留:
AS-IS:
Support depends more on current owner and local team knowledge.
TO-BE:
Support should move toward a shared team model,
with clearer responsibility and less dependency on one person.这也是我想和对方 argue 的一部分。
如果你担心系统老,我接受这个担心。但我们要看风险到底在哪里。是代码框架老,还是知识集中在少数人身上?是前端写法老,还是缺少监控和支持模型?不同风险对应不同动作。
如果问题是运维知识没有沉淀,那重写前端框架并不能解决。
会议不是为了赢
我现在更愿意把那次准备理解成一次“把技术问题从借口里拆出来”的训练。
如果总部明确说:我们想自己开发一套系统,因为后续治理、预算、团队分工或全球统一策略上有自己的考虑。这个理由可以讨论。
但如果理由变成“C# 太落后,所以中国这套系统技术不行”,技术方就必须把话说清楚。
因为这句话太容易传播,也太容易变成结论。它听起来像技术判断,但没有告诉你:
- 哪一层有风险。
- 风险有没有数据支持。
- 当前系统有没有经过安全和架构流程。
- 未来是应该升级、拆分、补监控,还是重写。
- 重写能解决哪些问题,又会引入哪些新问题。
- 如果总部要自研,和采用现有系统相比,成本和周期差在哪里。
所以我准备 PPT 时,想做的是把问题拆开。
从网络架构看,系统是否有扩展瓶颈。从应用技术架构看,当前技术栈是什么,未来怎么解耦。从安全评估看,风险项有没有被关闭。从运行数据看,系统当前有没有资源负载问题。从运维模型看,后续支持是不是过度依赖个人。
这些问题拆完之后,“老不老”反而没那么值得争了。
工程里更值得讨论的问题是:这个系统如果从 local 推到 global,最大风险在哪里?我们有什么证据?下一步是补架构能力、补治理能力,还是另起一个系统?如果选择另起系统,也应该承认那是组织和治理选择,而不是简单甩给 C#。
我带走的东西
这件事之后,我对技术沟通有了一个很具体的认识:不要急着反驳标签。
别人说“太老”,我可以解释 ASP.NET Core 和 .NET Framework 的区别,也可以解释 Vue.js 和 Razor 各自承担什么角色。但如果只停在这里,我还是在对方的语言框架里打转。
更好的方式是把标签拆成判断。
If the concern is framework support, check version and lifecycle.
If the concern is scalability, check deployment model and resource data.
If the concern is maintainability, check module boundary and support model.
If the concern is security, check assessment result and open actions.
If the concern is migration, compare upgrade, refactoring and rewrite cost.这段话后来也成了我处理类似问题的方式。
不是所有质疑都要硬顶回去。技术判断不是靠声音大,也不是靠把某个框架说得多先进。你要能把一个模糊评价拆成别人无法绕开的事实、风险和选择。
这才是我后来理解的 argue。
不是吵赢谁,而是让讨论回到该讨论的地方。
