现在任何一个具备一定商业或者技术价值的长期项目,都具备相当高的技术复杂度。这样的复杂度一方面是问题内在必需的,另一方面是偶然的,由其具体实现引入而决定。同样的问题,不同的工程实现,其偶然复杂度的含量有数量级的差别。
整体的复杂度决定了做这件事情的成本,比如时间和资金的投入。因为偶然复杂度的差异甚大,所以相同类型的不同项目,其投入成本的多寡也差别甚远。以至于偶然复杂度本身可以决定一部分项目可行性。比如不同的项目内,开发同一个feature的时间可能相差十倍,排查和修复同一个问题的时间可能相差十倍,这直接决定了成本。因而工程投资对于长期项目来说,是至关重要的。
除了直接的成本原因,工程上的改进还可以在其他方面形成良性循环。因为效率改进意味着形成快速的正反馈,容易验证和添加新的好的想法,并激发做出更多改进的motivation。反之如果在一个项目中的工作令人痛苦,那么这样的motivation很难存续。研发效率的改进会激发出超越研发效率本身的改进。研发效率的退化会次生出效率之外的腐败。这样优势本身可以形成技术上的壁垒,形成产品层面内在的核心竞争力。
管理和控制复杂度的技术方向,是为工程化的根本技术方向。工程化的基本工作内容,就是通过控制复杂度的技术和实现,来降低偶然复杂度的存在,改进必然复杂度的表达方式,以改进维护成本和正确性,以改进成本和提升效率。这样的改进具体 有诸多典型的评估方向,比如扩展性,维护性,可测试性,可调试性。这样的改进有诸多具体的形式,比如调整模块组织方式,提取典型的良性结构和pattern,落实最佳实践,改进抽象层次的设计。对于不同的具体问题,具体领域,工程研究有不同的具体课题
图形渲染领域有很多工程方向的问题,有很多天然存在的工程挑战。
图形渲染的主要工作,就是将顶层目标转化为底层支持的高效实现,其顶层和底层都本身都存在相当高的固有复杂度。从底层看,硬件厂商自古以来把图形api设计的繁杂晦涩,绘制一个三角形要上千行代码,赋予了上层建筑的相当多的设计自由。每年又有一些新的硬件能力通过新的api解锁,上层建筑要能够与时俱进的调整。产品因为跨平台的需求,又使得上层建筑需要支持多种平台。从顶层看,为了支持业务实现,需要维持一系列为业务服务的场景api,每年调整和严谨。又要支持诸多格式的交换。
开发一个功能简单的渲染器,根本不是问题。开发一个功能简单性能顶尖的渲染器,如果你知道正确做法,也不是问题。开发一个功能复杂且性能顶尖的渲染器,就有难度了。开发一个功能动态且复杂,性能在多种典型场景都表现优异,又能支持各种平台,又要适应各种潜在变更,那就很有难度了。当你开发一个核心feature,有可能需要思考之前n个feature的兼容性,作出这种正交性好的结构,是有挑战的。
我认为目前渲染器工程化研究是欠缺的,甚至是处于刀耕火种的时代。
- 普遍认为开发一个图形related feature是高成本,甚至是高风险的(从项目估计的角度)
- 工程方面的具体改进知识是runtim/ctx-specific的。正如同绝大多数图形工程师的招聘也是要区分untiy和unreal一样,具体的知识和已有的环境强关联。比如,问题往往是如何在unity下实现某feature,但是一个更加通用的问题无法有效提出。通用的,跨runtime ctx的思考的价值是更高的。
- 讨论的基础不明确。比如讨论跨runtime的问题时,交流为依据的基本概念有哪些,这并不明确。比如不同实现对场景的寻址的基本假设,对资源管理的基本假设都是不一致不明确的。
- 没有定义清楚存在哪些哪类具体的问题需要解决,整个领域本身处于一个混沌的状态。知识零散庞杂,缺乏从工程角度出发的分类整理和结构组织。
- 因为上述原因,实现和技术建设难以共享,使得不同公司,不同团队,不同项目之间有大量的封闭的重复建设。
为了解决其基本困难,我认为一个值得尝试方法论是:在一个runtime无关的,自研的ctx下。定义出渲染本身的通用的,若干工程centric的capability。指出这些capability的最佳实现方式,以及这些capability的内部之间的依赖和外部环境依赖,其工程建设的顺序(like skill tree)。形成一个基本的概念模型。
- 完善这样的skill tree 模型,作为渲染器工程建设的核心讨论环境
- 不同的平台支持,skill tree可以有如何的变体?
- 不同的业务特性,应该着重做哪一部分的技术建设?
- 现在应该做哪些工程投资,以服务于后续哪些顶层需求?
- 根据不同的场景业务特性来切换核心工程实现,以改进性能和消耗表现
- 讨论feature-wise的实现时,引用这样的概念模型来定义其实现的runtime依赖。
- 传统做实现时如果缺少前置工程依赖,往往会直接采用临时性的方案,导致引入大量偶然复杂度。而如果工程上的依赖被显式的定义和分析过,那么就可以提前避免这样的错误。同时提升了项目管理的成本估计正确性
- feature实现原理变成runtime agnostic
- 这种设计厘清了通用结构层面的耦合关系,可以使得某些具体的feature无关的工程主题实现可以被作为单独的模块实现和共享。改进重复建设问题。另外某些具体的工程建设也可以使得原先难以共享的实现被合理的共享。
- 利于横向对比具体实现,比如讨论其他业内实现的和runtime的工程水平。利于从其他实现中汲取工程价值(比如讨论某capability在某渲染器是如何实现的,代码在哪里),而不至于泛泛而谈。同时也有利于将上述runtime agnostic的feature实现移植到某具体runtime。
长期以来我始终听到工程部门和研究部门相互对立的观点。工程部门不需要注重和学习科学角度的技术原理,也不认可其做研究方向的投入尝试,只需要应付和解决业务的繁琐需求。研究部门不需要注重工程实践,也不认可其说做的工程建设,只需要发布研究成果。
两边各自埋头做自己的事情,然后往往有具体的项目排期出来,以将研究部门的开发成果,由工程部门在实际产品中重新精心实现集成。研究部门为了日常实验性质的开发能够高效推进,必然要自己投资做好一定的工程建设。由此两边都在重复招聘,重复建设一样的事情,这是我所见到的,典型的资源浪费。
这样错误的职能划分,或者错误的职能理解一旦出现,一旦运作起来事实上成为两个项目,就很难拆除掉。不仅技术上的整合形成了新的成本,更重要的是团队的合并裁撤存在政治上的巨大阻力。很难说两边的项目谁合并到谁,feature set,performance,工程质量的综合因素几乎没有什么可能得出另所有人信服的说法。总之这种现象如果出现标志着公司技术管理上非常糟糕的信号。
工程和research的合理关系,应该是research团队完全使用工程团队的基础设施,工程团队完全接管和服务research的工程需求。research的成果,经过简单调整和修改就可以直接进入production。任何工程建设都能利于research的日常研究。
因为知识大都是开源的,对于比较成熟的领域,研究上的投资可能会产出非常有限,大部分技术产品的竞争力并不以研究来推动,其价值也很少很少体现在我可以做到而别人不行的地步。又因为长期项目的工程实现决定了研发成本,所以我甚至认为工程方向的research很可能价值远高于传统的research。
这种工程方向的research,似乎并不是一个常见的职业定位。人们往往认为复杂工程问题不是一个严肃的干净的研究课题,甚至都没有意识到其必要性。这种工程方向的研究,即便不考虑其最终目,也是货真价实的研究:发现乃至定义问题,提供分析和解释,提出解决方案。研究的目标是非常显示的具体项目具体问题。作出的改进直接作用于具体项目解决具体问题
在当下越来越多的图形项目放弃采用自研实现。我认为这是容易理解的,原因在于普遍高额投入和产出的不平衡。
如果处于验证商业模型阶段,性能和体验不是核心因素。那么就没有必要自研。所谓不是核心因素就是,开源方案没有能提供这样的技术(根本没有这么绘制的,活着根本没有画的这么快的),而这个技术决定了这个东西的存在性。比如你做了一个基于距离场 f-rep的建模软件,用户用这种方式建模非常快非常好,但是你根本找不到一个渲染器能支持以合理的成本实时渲染超级复杂的距离场表达式。
如果你没有足够的资源投入,那么也别考虑自研。因为投入非常高昂。如果你没有找到靠谱的人,那么也别考虑自研。因为比如工程上没有能力又没有核心技术壁垒(现在又有什么呢)的结果,就是做出非常勉强和脆弱的东西。这种东西长期来看,是没有价值的,人走茶凉无人维护之后,反而是技术债务。
综合不同的因素,比如投资,人才,商业需求,可以说现在很多自研渲染器实际上没有存在的价值。有些虽然有去做的先决条件,但是产出很难说形成了核心优势。
我只能说希望图形领域的工程化研究,其相关的知识沉淀,乃至新的以能力组件为入口生态的形成,能够长期的改善这种高成本低产出的不平衡现状。如果说搜索相关问题的资料和最佳工程实践比现在容易十倍,如果说一个结构足够良好的渲染器框架,来支持不同自研实现使得feature开发成本比现在减少十倍,如果说因为某产品的图形能力提前形成了差异化的竞争优势,图形显示要求越来越高越来越定制化,或许有一点可能吧。