提问回顾
-
关于 10 个问题
-
为什么说软件是人类创造的最复杂的系统类型?大型建筑、飞行器甚至长篇小说的结构也可以非常复杂,并且容易变得难以理解和维护,认为软件系统十分复杂是不是因为软件工程还没有充分发展?
-
从工程量上
-
代码行数统计: https://informationisbeautiful.net/visualizations/million-lines-of-code/
-
单纯从代码行数来看,许多大型工程的代码行数都比作为生物的细菌要多。虽然我们自己写的程序可能不超过几千行,但是人们经过长时间合作写成的代码却可以规模非常庞大。如此庞大的代码,光是单纯的通读一遍都需要耗费很长时间,更何况对其进行结构分析和正确性的判断。
-
-
从结构复杂性上
- 一般的程序语言虽然层次结构没有特别复杂的元素,过程上包含顺序、条件、循环和函数调用,对象上有继承关系等,但是这些简单的元素进行组合就可以形成非常复杂的层次结构。当我调用一个函数的时候,函数可能去调用别的函数,甚至去修改一些全局变量造成副作用。对于多层调用的函数,要去阅读其语义就要读懂它调用的函数的语义,如此递归下去。编写的时候,编写者需要思考好每一层调用如何定义其功能,如何适当地分层来提高代码的复用性,这些都是非常难以规划的问题。调试的时候,错误可能基于各种各样的影响,甚至是由于并非自己所写的函数造成的影响。各种顺序、条件、循环也会由于修改了共享的内存而互相影响。从编写一般过程性结构的程序来讲,都不是告诉计算机“要去做什么”,而是要“教计算机怎么去做”,这一过程基本上需要人来通过编程语言给出一个框架,这时就会容易产生错误。在实用的软件中,往往还有很多异常情况需要处理,这些情况嵌入到这些结构,又会使结构变得更加复杂。
-
从团队合作上
- 大型软件的编写不能光靠单枪匹马,而是需要团队合作。越大型的软件,就需要越大型的团队进行越复杂的团队合作。人类是复杂的生物,建立团队本身就是非常困难的事情,如何说服一帮有才能的人加入到团队中,如何分配工作,如何保持团队的凝聚力,各个模块之间的开发如何并行化如何对接,等等,都是不仅仅和计算机相关的问题。
-
从服从性上
- 任何软件的编写都不是为了编写软件的自身,而是为了服务于客户的需求。而需求是很容易变更的东西,开发的过程中可能由于需求的变更导致整个架构失效;要建立一个灵活应对变更需求的框架,就是非常困难的事情;现实中要考虑到的问题也不仅仅是计算机上是否正确的问题,虽然计算机本身已经行为非常复杂了,但开发一个软件还要考虑它在现实中要处理的复杂问题。比如要考虑建立一个学生成绩的管理系统,我们就不能只考虑建立这样一个表去存储成绩,还要考虑数据库的安全性,还要考虑到成绩的修改(由于各种人为错误需要修正),这又引申到一堆问题,比如谁来裁定修改的公正性,谁来执行修改的动作,什么样的情况是可以修改的,等等,这些东西在软件上的映射都已经远远超出了原来的范畴。
-
-
用形式逻辑的方法验证需要高可靠性的大型软件的正确性是否可行?例如航空的软件系统。
- 已经有形式逻辑验证的先例:一种面向安全关键软件的程序证明方法研究(曲长亮,2014)。在论文中,作者对嵌入式安全关键软件进行了语法树的分析,从而得出软件系统的形式逻辑约束。但是整个过程使用的是C语言的安全子集Safety-C进行编写,单这一条在商业环境快速开发快速部署的环境下,就是不可行的,对于不安全的C语言和各种行为无法预测的动态语言的分析,构建一个合理的形式逻辑方法还是任重而道远。
-
如何发现社会的潜在需求?类似小黄车这样的项目,之前从未有人提出来过,这种颠覆性的创新是如何提出并且恰好被市场认可?
- 这个问题我认为很难给出答案,毕竟给出了答案的人肯定不会告诉我,他会自己去创业然后赚钱(233)。但事实上发现潜在需求的方法也不是无迹可寻。小黄车的创始人就是发现了出行中的“最后一公里”是一个没有被填充的需求。最后一公里,用腿走太慢,用车走又开销太大,骑自己的单车又需要管理车的停放等问题(例如旅行前到车站的最后一公里,你的单车停在哪里都不是很安全)。这样就出现了共享单车,用户可以以经济的方式骑车,同时不需要特别费心地管理车的位置。
-
为什么作者坚持认为代码应该手写?用技术提高写代码的效率,除了造轮子,实现代码的自动生成是否也是一条出路?
-
代码手写,从本质上来讲就没有道理。按照这种说法,我们应该直接去写汇编语言。我的理解是,机器自动生成的代码和人类手工生成的代码必须分开,同时机器自动生成的代码需要对其进行语义的概括性描述,即我们需要把机器生成的代码封装起来。原因是,人类生成的代码与机器生成代码最大的不同点就是人类代码不仅仅可以编译成低级的指令,还包含了丰富的语义信息,可以被阅读,而再高明的算法产生的代码,通常都一行一行去处理各种细节,人去阅读它们,都会深陷到细节中而无法理解。
-
对于什么时候使用自动生成代码,我认为在以下两种情况是可行的:
- 语言不好用,以至于描述某些有共性功能涉及到的无脑细节太多,需要机器生成来避免重复劳动;
- 语言不好用,描述很多没有共性的功能时需要解决同一个比较繁杂的问题,比如JS里的“a == b",对于这种问题,我们通常去写一个编译器把它编译成这个不好用的语言,比如typescript。
最理想的情况当然是使用的语言表意能力足够强,而我们不需要自动生成代码就可以直接避免重复劳动。但是现实很骨感,有些领域还没有很好用的工具来避免这些重复劳动,这个时候使用代码自动生成就没用问题。事实上编译就是一种代码自动生成技术,也有不少编译器是把语言编译成js的,并且有一定的实用性。可以说,代码自动生成技术是计算机行业的根基之一,但是我们要合理使用它,不要把机器的代码和人类的代码混在一起,才能有好的可读性和好的可维护性。
-
-
作为领导者,当团队急需看到成就时,是应该更多依赖直觉快速决策还是依赖分析决策?
- 如果是急需看到成绩,那么我觉得按照直觉并没有错,过度依赖数据提供的决策支持,那么很多时候做决定的不是人脑而是电脑。我们要看到电脑在分析繁复的现实中其实还是能力非常有限的,我们可以去网上查到高频词汇来判断现在流行什么,但是我们永远不可能知道这些词汇的上下文是什么。领导者具有丰富的人生经验,很多分析通过潜意识完成,但确实是人类不可思议的才能的体现,这种综合各种维度的分析能力并不能被显式的逻辑推出,但是得出这种决策通常非常快速而不会贻误战机。
-
Program Manager 如何保持和开发、测试、UX等人员平等的地位?如果PM负责统筹规划,其他人员是否还是他实际意义下的下属?如果PM和DEV发生不可调和的分歧,该听PM的吗?
-
在团队开发的过程中,我们发现,在队伍不是很大的时候,PM和其他人员确实没有任何地位高低的关系。从本质上,PM是其它人员的服务者,PM需要进行给出项目的需求、项目人员之间的协调等服务,同时要把握大局,管理进度。作为一个合格的PM,他对技术一定是了解的,他知道每个开发人员、测试人员、美工都在做什么,知道每个人负责的模块是在干什么,以及模块之间的关系。当紧急情况下,比如出现重大bug,或者临近DDL,有调度组员的能力。PM的存在,本质上是为了降低各个人员之间的沟通成本,起到凝聚团队的力量。比如当负责模块A的开发人员认为原来模块B和模块C有设计不理解的地方,但模块A的人员对模块B和模块C的构架不了解,他就不需要召集模块B和模块C的人员,可以直接去找PM反映这个问题,当PM对系统了解足够时,就不需要PM去惊动另外两人。
-
当PM出现了不称职的行为,或者给组员的压力不合理,每个组员当然可以坐下来和PM交流,对PM的工作提出建议。实际上,在小团队中,大家知识和实力都差不多,每个人都希望能开发出优秀的产品,就不可能存在PM独裁或者不称职的情况,因为PM令行禁止的前提是组员相信PM分派的任务是对的,PM让我干的事情是为了团队能开发出更好的产品,而不是为了他自己的利益。从这个观点来看,PM并不是“上司”,而是公仆、顾问。软件团队的模型和现代国家存在很大不同,组员之间是出于共同的目标走到一起,并且由于其他人拥有的知识和能力而互相尊重,这种情况下不平等的情况是不存在的。
-
-
该如何控制项目的风险?特别是在中国当前的经济、文化政策下,很难预知软件发布时是否出台了更严格的审查政策,在这样的环境下,如果资金和人力不丰厚,如何保持项目的健壮性?
- 我觉得还是发布到 steam 上吧,实在不想被这些政策羁绊手脚。
-
客户不断增加新需求,打乱开发流程该怎么办?如何让软件架构适应不断变化的需求?
- 在设计模块的时候,尽量让各个模块之间不要互相干扰,保持独立性,这样当需求变更的时候,只需要重写受到影响的模块;使用快速开发的语言,比如Python,可以用一个名字表示各种类型的变量,便于及时的修改;写程序的时候减少硬编码,把类似参量的东西统一起来管理,便于适应需求的变化;传递参数用灵活的格式进行,比如JSON。
- 在开发评测机的时候,针对后序的评测需求,需要修改评测脚本,修改传入参数并进行灵活的调整。这都通过使用 Python 和 JSON 格式灵活修改参数来做到。
-
一般的项目经理需要怎样的技术能力?工程师觉得项目经理不懂技术,不服领导,是否有道理?项目经理是否应该有足够的技术功底?
-
懂技术有时候会是天然的优势,可以帮助项目经理更好的分析交付物,进行工作结构分解,理解过程和风险识别及管控,与团队沟通时障碍较少,相应的可以降低一些对于沟通能力的要求。但特别需要注意不要陷入技术细节的纠缠中,导致忽视全局总体判断;还有不能以技术专家自居,项目技术工程师可能会抱怨你越俎代庖。要尊重从技术工程师角度给出的技术性意见,如果你有技术方面的疑虑,可以真诚的与技术进行讨论但千万不能强压,如果不能说服可从项目角度出发评估风险和制定应对措施。(https://www.zhihu.com/question/54011522/answer/137970031)
-
如果是不懂技术的项目经理,应该尽量少在技术上直接指导工程师,应该发挥管理上的能力才能得到技术人员的认可。项目经理要想继续长期干下去,还是应该对技术有一定的了解,不需要自己会写代码,但应该懂得技术人员各个模块是怎么联动的。
-
-
作为以编程为生的程序员,在这个人人会编程的年代,保持不可替代性的方法,除了学习软件工程等专业开发知识,还有什么?
- 我觉得程序员最不可替代的地方就是丰富的编程经验,这包括对语言的知识,对各种框架的熟悉和应用,对计算机基本原理的熟悉,以及构建大型工程的能力。其他学科的人员或多或少也会编程,但是他们的编程实际上是在应用一些比较专用的工具,去完成计算机以外的工作,而不是从构成软件工程的角度去编程。
-
-
提出新的问题:
- 现在的许多通讯方式都是用的纯文本内容,比如命令行是字符串,参数用JSON传递,网页用XML描述。字符串的缺点是信息熵太小,非常浪费空间,如果二进制传输能成为主流,是否会提高很多效率?难点在哪里?
-
学到的知识点:
-
需求阶段:需求分析非常重要,没有需求就没有“题目”,程序员要“做题”就无从谈起。不同的项目具有不同的需求特点,游戏的需求分析尤其特殊,因为本质上用户“没有”游戏的需求,而是我们为用户创造去玩我们设计的游戏的需求。我们之前把游戏的需求分析都交给一个人做,压力太大。
-
设计阶段:做决定要趁早,要果断,时刻准备在实现阶段返工。
-
实现阶段:需要选择正确的IDE,选择正确的框架,才能提高协作的效率。切割任务是非常难的过程,好的分割让任务之间依赖最小化,方便并行开发和对接。开发后开发人员应该对自己的模块进行单元测试,才能在对接的时候减少玄学问题。
-
测试阶段:一定要选择方便测试的框架,框架选不好测试会变得非常困难,测试要早做,要编写者自己先做,commit的时候至少commit当前看来稳定的版本。
-
发布阶段:一定要趁早实现产品,这样才有充足的时间去发布,去收集用户反馈,选择合适的平台也很重要。
-
维护阶段:收集用户反馈再去解决问题,比测试人员自己测试更有效率
-