ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

编程尚未被解决:意图与指令的鸿沟及开发者应对策略

编程尚未被解决:意图与指令的鸿沟及开发者应对策略

1. 为什么“编程尚未被解决”不是一句空话

如果你在这个行业里待过几年,大概会注意到一个反复出现的现象:每隔一段时间,就会有人宣布“编程已经被解决了”。从早期的可视化编程工具,到后来的低代码平台,再到近几年各种智能代码生成工具,每一次技术浪潮都会带来类似的论调。但如果你真正在一线写过生产代码,你就会知道,这个说法离现实还有相当远的距离。

“编程尚未被解决”这个判断,不是对现有工具的否定,而是对问题本质的一种清醒认知。它说的是:我们至今仍然没有找到一种方式,能够让人类用足够低的成本、足够高的可靠性,把脑海中的意图转化为机器可以执行的指令。这个转化过程,就是编程的核心难题,而它至今没有被根本性地解决。

我之所以想认真聊聊这个话题,是因为它直接关系到每一个从业者的日常决策:你该把时间花在学什么上?你该信任哪些工具?你该对哪些承诺保持警惕?这些问题没有标准答案,但如果你理解了“编程为什么还没被解决”,你至少能做出更清醒的判断。

这篇文章适合所有对编程这件事有长期投入打算的人——不管你是刚入行的新手,还是已经写了十年代码的老手。我不会给你一个“未来已来”的乐观叙事,也不会唱衰任何工具。我想做的,是把这个问题拆开,看看它到底难在哪里,以及这些难点对我们意味着什么。

2. 编程的核心难题:意图与指令之间的鸿沟

2.1 人类意图的模糊性与机器指令的精确性

编程的本质困难,首先来自一个根本性的不对称:人类的意图是模糊的、上下文相关的、随时可调整的,而机器指令是精确的、无歧义的、必须提前确定的。

你让一个人“把房间收拾一下”,他能根据房间的实际情况、你的语气、你们之间的关系,自动推断出很多你没有说出来的约束。但如果你给机器下同样的指令,它需要你明确定义“收拾”的范围、标准、顺序、异常处理方式。编程语言和框架的每一次进化,本质上都是在试图缩小这个鸿沟——让人类用更接近意图的方式表达,让机器自动补全那些精确的细节。

但这里有一个绕不开的矛盾:表达越接近人类意图,机器需要自动补全的细节就越多,而这些自动补全的决策,未必是开发者真正想要的。这就是为什么声明式编程、领域特定语言、代码生成工具,虽然在某些场景下极其高效,但一旦需求偏离了工具预设的轨道,开发者就会发现自己陷入了一种更麻烦的境地——你不仅要理解业务问题,还要理解工具的内部模型,才能找到正确的“咒语”让工具按你的意图工作。

2.2 上下文依赖:为什么代码不能像数学公式一样独立存在

很多人把编程类比成数学,认为只要逻辑正确,代码就应该正确。但真实世界中的代码,从来不是孤立存在的。一段代码是否正确,取决于它运行的上下文:它依赖的库的版本、它运行的环境、它处理的数据的特征、它与其他模块的交互方式。

这意味着,即使你写出了逻辑上完全正确的代码,它仍然可能因为上下文的变化而失效。一个在开发环境跑得好好的服务,到了生产环境可能因为并发量、网络延迟、数据规模的变化而崩溃。一个在单元测试中通过率百分之百的函数,到了真实数据面前可能因为边界条件处理不当而产生错误结果。

这种上下文依赖性,是编程无法被“解决”的另一个根本原因。因为上下文是无穷无尽的,你不可能在写代码的时候考虑到所有可能的运行环境。你只能基于经验做出假设,然后通过测试、监控、日志来验证这些假设是否成立。而这个过程,本质上是一个持续的实验和调整过程,不是一个可以被一次性“解决”的问题。

2.3 需求本身在编写过程中不断演化

还有一个经常被忽视的难点:需求不是先于编程存在的固定目标,而是在编程过程中不断演化的。用户一开始说“我要一个能统计用户数量的功能”,等你做出来之后,他可能会说“我还想看到每天的变化趋势”,然后是“能不能按地区拆分”,然后是“能不能预测下周的数据”。

每一次需求变化,都意味着代码需要调整。而代码的调整成本,随着系统复杂度的增加而指数级上升。这就是为什么很多项目会陷入“越改越慢、越慢越改”的恶性循环。不是开发者不够聪明,而是编程这件事本身就没有为“需求持续变化”设计一个好的应对机制。

敏捷开发、持续集成、微服务架构,这些方法论和架构模式,都是在试图降低需求变化的成本。但它们只是缓解了问题,没有解决根本矛盾。因为根本矛盾在于:人类对问题的理解是渐进的,而代码一旦写出来,就变成了一个需要维护的资产。你不可能让代码像人类思维一样灵活地随时重构。

3. 那些声称“解决编程”的方案,到底解决了什么

3.1 低代码平台:把编程变成了配置

低代码平台是近年来最常被拿来讨论“编程是否被解决”的例子。它们的核心思路是:把常见的业务逻辑抽象成可视化组件,让开发者通过拖拽和配置来搭建应用,而不是从零写代码。

这个思路在特定场景下确实有效。比如企业内部的管理系统、简单的表单流程、数据展示页面,用低代码平台可以大幅缩短开发周期。我见过一些团队用这类工具,把原本需要两周的开发任务压缩到两天完成。

但问题在于,低代码平台解决的是“常见场景的快速实现”,而不是“编程本身”。一旦你的需求超出了平台预设的组件范围,你就需要写自定义代码来扩展。而一旦你开始写自定义代码,你就又回到了传统编程的困境中——你需要理解平台的扩展机制、处理平台版本升级带来的兼容性问题、调试平台内部的黑盒行为。

更关键的是,低代码平台把复杂度从“写代码”转移到了“理解平台”。对于简单场景,这个转移是划算的;但对于复杂场景,你只是在用一种复杂度换另一种复杂度,并没有真正消除编程的困难。

3.2 智能代码生成:补全的是片段,不是意图

智能代码生成工具是另一个热门方向。它们可以根据注释、函数名、上下文,自动生成代码片段。在实际使用中,这些工具确实能提升效率,尤其是对于样板代码、常见算法、API调用这类有大量先例的场景。

但如果你仔细观察这些工具的工作方式,你会发现它们本质上是在做“模式匹配和概率补全”。它们根据海量代码库中的统计规律,预测你接下来最可能写什么。这意味着,它们擅长的是那些“已经被写过很多次”的代码,而不是那些“需要根据具体业务逻辑做独特设计”的代码。

换句话说,智能代码生成工具解决的是“打字效率”问题,而不是“编程思维”问题。它们可以帮你更快地写出你已经知道怎么写的代码,但当你面对一个全新的问题、需要设计一套新的抽象、需要权衡不同方案的取舍时,它们能提供的帮助就非常有限了。

3.3 为什么这些方案都只是局部优化

把低代码平台和智能代码生成工具放在一起看,你会发现它们有一个共同特征:都是在编程的某个局部环节上做优化。低代码优化的是“常见业务逻辑的实现”,智能代码生成优化的是“代码片段的编写速度”。

但编程是一个端到端的活动,它包含了需求理解、方案设计、代码编写、测试验证、部署运维、迭代维护等多个环节。任何一个环节的优化,都不能代表整个编程活动被“解决”了。就像你发明了一种更快的打字机,不代表写作这件事被解决了一样。

真正要“解决编程”,需要的是让整个端到端流程都变得足够简单、足够可靠、足够低成本。而目前我们看到的,只是在某些环节上取得了进步,离整体解决还有很长的路要走。

4. 从实际项目经验看编程难在哪里

4.1 一个看似简单的需求,为什么写了三天

我参与过一个内部工具的开发,需求听起来很简单:从几个数据源拉取数据,做汇总计算,然后生成一份报告。按照常规估计,这种任务大概一天就能完成。

但实际做下来,花了三天。第一天花在了数据源的对接上——其中一个数据源的接口文档不完整,字段含义需要反复确认,还有一个数据源在特定条件下会返回空值,需要做额外的容错处理。第二天花在了汇总逻辑上——业务方对“汇总”的定义在不同场景下不一样,需要和他们反复沟通才能确定规则。第三天花在了报告的格式上——生成的报告需要适配不同的查看终端,还要考虑数据量大的时候的性能问题。

这个经历让我深刻体会到:编程的困难,很少来自“写代码”本身,而是来自代码之外的那些东西——不完整的文档、模糊的需求、意料之外的边界条件、不同利益相关者的不同期望。这些东西,不是任何工具能替你解决的。

4.2 代码审查中暴露的认知差异

另一个让我意识到编程尚未被解决的场景,是代码审查。同一个功能,不同开发者写出来的代码可能完全不同。有人喜欢用设计模式,把代码结构搞得非常规整;有人喜欢直截了当,用最少的抽象完成任务。这两种风格没有绝对的对错,但它们反映了编程中的一个深层问题:我们至今没有一套公认的、可操作的“好代码”标准。

你可以说“可读性重要”,但什么是可读性?对于熟悉设计模式的人,模式化的代码更可读;对于不熟悉的人,直白的代码更可读。你可以说“可维护性重要”,但什么是可维护性?是容易修改,还是容易理解,还是容易测试?这些目标之间经常是冲突的。

这种认知差异的存在,说明编程仍然是一门高度依赖个人经验和判断的手艺,而不是一门可以被标准化、自动化的工程学科。只要这种差异存在,编程就不可能被“解决”。

4.3 生产环境中的意外:编程的“最后一公里”问题

还有一个经常被低估的难点:从“代码能跑”到“代码在生产环境稳定运行”,中间有一条很长的路。这条路上充满了各种意外:内存泄漏、并发竞争、网络抖动、磁盘满了、依赖的服务挂了、流量突增、数据格式变了。

这些问题,在开发环境和测试环境中往往不会暴露,只有在真实的生产环境中才会出现。而解决这些问题,需要的不仅仅是编程能力,还需要对系统行为的深刻理解、对监控数据的敏锐解读、对故障的快速定位能力。

我见过很多项目,代码写得漂亮,架构设计合理,但一上线就各种问题。不是开发者水平不行,而是生产环境的复杂性超出了任何人在编写代码时能预见的范围。这种“最后一公里”的困难,是编程无法被“解决”的又一个有力证据。

5. 编程的未来:不是被解决,而是被重新定义

5.1 从“写代码”到“描述意图”的渐进迁移

虽然编程不会被“解决”,但它确实在演化。一个明显的趋势是:开发者越来越多地在描述“要什么”,而不是“怎么做”。声明式配置、基础设施即代码、意图驱动的开发流程,都在推动这个方向。

但这不意味着“写代码”会消失。更可能的情况是,代码的抽象层次会继续提高,开发者需要关注的细节会继续变化。今天你需要手写内存管理,明天你可能需要手写并发控制,后天你可能需要手写数据一致性策略。每一层抽象都隐藏了下面的细节,但同时也引入了新的、更高层次的复杂性。

所以,与其说编程会被“解决”,不如说编程的难点会不断迁移。旧的问题被工具消化了,新的问题又会出现。这是一个永无止境的过程,而不是一个有终点的旅程。

5.2 开发者角色的演变:从实现者到决策者

随着工具能力的提升,开发者的角色也在变化。过去,一个开发者的核心价值在于“能写出正确的代码”;现在,这个价值正在向“能做出正确的技术决策”转移。

你需要决定:用什么架构、选什么技术栈、如何划分模块、如何设计接口、如何保证质量、如何控制成本。这些决策的质量,往往比代码写得快不快、漂不漂亮更重要。而做出好的决策,需要的是对业务的理解、对技术的判断、对风险的评估,这些都不是工具能替代的。

这意味着,未来的开发者需要更宽的视野、更强的判断力、更好的沟通能力。编程这件事,正在从“手艺”向“决策”迁移。而决策这件事,恰恰是最难被自动化的。

5.3 为什么“解决编程”可能是一个错误的目标

最后我想说的是,“解决编程”这个目标本身可能就有问题。编程之所以有价值,恰恰因为它是一种通用的、灵活的、可以表达任意逻辑的工具。如果有一天编程真的被“解决”了,那意味着我们只能用某种预设的方式来表达意图,而无法自由地创造新的逻辑。

这就像问“写作什么时候能被解决”一样。写作永远不会被解决,因为写作的本质是表达思想,而思想是无穷无尽的。编程也一样,它的本质是描述计算过程,而计算过程的可能性是无穷无尽的。

所以,与其期待编程被解决,不如接受它永远不会被解决这个事实,然后把精力放在如何更好地与这种复杂性共处上。这才是对开发者真正有价值的思考方式。

6. 面对“未被解决”的编程,从业者该怎么做

6.1 把学习重点从语法转向问题建模

如果你认同“编程尚未被解决”这个判断,那么你的学习策略也应该相应调整。不要把大量时间花在记忆语法细节和API用法上,这些知识会过时,而且工具会帮你补全。把时间花在提升问题建模能力上——学会把模糊的需求转化为清晰的计算问题,学会识别问题的核心约束,学会设计合理的抽象。

这种能力,不会因为工具的变化而贬值。相反,工具越强大,这种能力就越重要。因为工具只能帮你实现你已经想清楚的东西,而想清楚这件事,永远需要你自己来完成。

6.2 培养对复杂系统的直觉

编程的困难,很大程度上来自系统的复杂性。你需要培养一种对复杂系统的直觉:知道什么地方容易出问题,知道什么指标值得关注,知道什么情况下需要停下来重新思考。

这种直觉,不是从书本上学来的,而是从实际项目中积累的。每解决一个生产问题,每排查一个疑难故障,每重构一个混乱的模块,你的直觉就会增强一点。所以,不要害怕遇到问题,问题才是最好的老师。

6.3 接受不完美,持续迭代

最后,也是最重要的:接受编程中的不完美。你写的代码永远会有bug,你的设计永远有改进空间,你的方案永远不是最优的。这不是你的失败,而是编程这件事的本质决定的。

与其追求一次写出完美的代码,不如建立一套持续迭代的机制:写测试、做代码审查、监控生产环境、收集反馈、定期重构。这套机制不能消除问题,但能让你在问题出现时快速发现、快速修复。

编程尚未被解决,这意味着你永远有成长的空间,永远有新的东西可以学。这既是挑战,也是这个职业的魅力所在。我在实际工作中越来越觉得,与其焦虑于“我是不是会被工具替代”,不如把精力放在那些工具替代不了的能力上——理解问题、设计方案、做出判断、持续学习。这些能力,才是你在任何技术浪潮中都能站稳脚跟的根本。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进