思维 程序员 逻辑 我们在平时的产品实现过程中会经常与产品吵架,与开发撕逼。这是因为我们这些产品实现的参与者因为分工不同都有很强的边界感,这种边界感同样也体现在思维模式上。产品经理看待问题是以产品思维来思考;设计师做设计时也是以设计思维来思考;程序员更多是以代码实现的程序员思维来思考。不同的思考方式,难免会出现不同的理解,同时也会出现描述问题时完全不懂对方在说什么。作为设计师,除了本职工作必须具备的设计思维外,更多的是要求我们需要有产品思维,将产品思维运用到日常的产品设计工作中,却很少见到设计师去了解或掌握开发思维。当然从开发实现角度来做设计俨然不现实,但是否可以运用程序员思维来服务设计呢,个人觉得是可以的。将程序员的思维方式应用到产品的设计实现中,是能够提升产品体验和提高团队协作效率的。更多思维:小心成为设计机器!高级设计师都应该掌握的4种思维方式最近几年,人工智能的快速发展,正在逐渐取代部分低端的设计工作。阅读文章 > 一、什么是程序员思维什么是程序员思维?没有标准答案。马克思·韦伯在《新教伦理与资本主义精神》中提出过一个概念——工具理性。所谓“工具理性”,就是通过实践的途径确认工具(手段)的有用性,从而追求事物的最大功效,为人的某种功利的实现服务。工具理性是通过精确计算功利的方法最有效达到目的的理性,是一种以工具崇拜和技术主义为生存目标的价值观,所以“工具理性”又叫“功效理性”或者说“效率理性”。相似的,编程也是根据客户的需求,利用自己的专业技能将其编译成计算机语言,生产出一个软件产品,来帮助解决现实生活中的问题,从而实现产品的商业价值。因此,可以将程序员思维定义为是在理性思维的框架下,利用相应工具,来解决相应实际问题。二、程序员一般都具备哪些思维1. 底层思维能力:逻辑思维处于不同阶段的程序员所具备的思维能力会有所不同。但作为以逻辑思维缜密自居的程序员们,逻辑思维算得上是他们最底层的一种思维能力。其实任何人都应该具备一定的逻辑思维能力,这样在面对“杠精”的时候,能发现对方的逻辑谬误;在思考问题的时候,能尽量做到逻辑完整;在表达的时候,能尽量做到逻辑清晰。那什么是逻辑,逻辑的起源经历了从自然哲学到形而上学的发展,我们也无需深究其发展过程。借用大师的总结,逻辑是指思维的规律和规则。或者更简单的理解,逻辑就是关系。逻辑思维基本包含三个方面的要素:概念、判断和推理,逻辑思维的要义,就在于正确运用概念、判断、推理的思维形式。概念是思维的基本单位;通过概念对事物是否具有某种属性进行肯定或否定的回答,这就是判断;由一个或几个判断推出另一判断的思维形式,就是推理。实际上阅读一本书的逻辑也是包含这三个要素,如果你看过《如何阅读一本书》,里面提到的分析阅读,说的就是如何通过提炼一本书的关键字词(概念),关键句子(判断),以及关键论述(推理)来分析一本书的主旨。2. 必备思维能力:抽象思维和结构化思维程序员每天面对的工作并不只是简单的敲代码,而是需要对拿到的需求及问题进行分析、归纳、综合、判断、推理。从而抽象出各种概念,挖掘概念和概念之间的关系,对问题进行有序建模,然后通过编程语言实现业务功能。这里面就需要应用到抽象思维和结构化思维。① 抽象思维抽象是有层次性的,抽象层次越高,内涵越小,外延越大,扩展性越好;反之,抽象层次越低,内涵越大,外延越小,扩展性越差,但语义表达能力越强。我们可以根据毕加索的画《公牛图》来理解一下抽象思维:抽象的三个特点:第一,抽象是忽略细节的。抽象类是最抽象的,忽略的细节也最多,就像抽象牛,只是几根线条而已。在代码中,这种抽象可以是 Abstract Class,也可以是 Interface。第二,抽象代表了共同性质。类(Class)代表了一组实例(Instance)的共同性质,抽象类(Abstract Class)代表了一组类的共同性质。对于我们上面的案例来说,这些共同性质就是抽象牛的那几根线条。第三,抽象具有层次性。抽象层次越高,内涵越小,外延越大,也就是说它的涵义越小,泛化能力越强。比如,牛就要比水牛更抽象,因为它可以表达所有的牛,水牛只是牛的一个种类(Class)。② 结构化思维结构化思维,是一种以逻辑(事物内在规律)为基础,从无序到有序,将搜集到的信息、数据、知识等素材按一定的逻辑进行分析、整理,呈现出有序的结构,继而化繁为简的思考过程。其目的是减少复杂度和认知成本。举个简单的例子说明结构化思维,尝试用 10 秒钟记住下面 20 个数字:估计大多数人都很难在限定时间内记住。但换一种方式,同样让你 10 秒钟记住下面的这 20 个数字:是不是 so easy,甚至完全不用 10 秒,扫一眼就可以记住了。事实上,这是两组相同的数字,只是排列方式不同,第一组是无序的,第二组是有序的(有结构),也更有规律。我们之所以能够轻松记忆第二组数字,是因为其有结构、有规律,从而降低了复杂度和记忆负担。面对无序的 20 个数字,我们需要记住 20 个记忆项目,套用设计心理学中的 72法则「米勒定律」,人类短暂记忆无法容纳7个以上的记忆项目,因此我们很难记住这一组数字。用超多案例,帮你认识无处不在的「米勒定律」今天给大家带来一个无处不在的定律,虽然它很常见,但它很安静。阅读文章 > 而正序排列的 20 个数字,我们实际上只要记忆两个项目:一个是有 0 到 9 的 20 个数字,另一个是他们是正序排列的。说到结构化思维,其实运用最多的要属结构化思维的圣经——芭芭拉·明托的《金字塔原理》。至于为什么是金字塔结构,大家可以自行去了解。三、程序员思维与设计思维的不同设计思维,本质上是一种以人为本的问题解决方法。这里所说的设计是广义的设计,是以探索人的需求为出发点,创造出符合其需求的解决方案。与传统解决问题的方法不同的是,设计思维是面向过程的解决方案,而且是一个没有标准答案的探索过程。面对问题我们需要深入理解问题,这是一个发散的思考,从多方面了解问题发生的原因,然后归纳出问题的关键点。解决问题时也需要探索各种解决问题的可能性,具有创造性的给出合理的解决方案,并从中收敛选择最佳解决方案。其实通过“双钻模型”就能很好的理解这一过程。如何用好设计双钻模型?来看 vivo 浏览器的实战案例!前言刚入职时,有本书叫《方寸指尖》对我影响比较大,主要讲述如何做好用户体验设计。阅读文章 > 以人为本:认识到一切问题归根结底都是人的问题,从不同视角出发,对具体的人进行共情,而不是对抽象的事进行处理。信息澄清:以人为中心重新组织和定义问题。在信息澄清通常可以用一句话来描述问题:谁?(用户 User)有什么需要?(需求 Need)我发现了什么?(洞察 Insight),简称 POV 法。让大家对问题形成统一的认识,因为在讨论问题时,不同人理解与表达能力会有区别,造成的误会可以在过程中逐渐排除。可视化:可以表现更多信息间的关系,更易被记忆和传递,让信息共享效率更高。反复迭代:认识到设计过程中的不确定性与灵活性,反复迭代是一种非线性目标向线性流程妥协的变通做法。在实际应用上,我们需要不断的明确收获然后继续推进下去。简单了解设计思维后,我们可以简单总结程序员思维与设计思维的不同之处:程序员思维在解决问题时多为趋于严谨的线性推理,而设计思维则更趋向于创造性,多线并行的发散性思维解决方案。某些共性问题的解决方案上,程序员需要提炼更抽象的特征从而能够做到结构更加清晰;而设计需要从不同视角考虑,对具体问题面向对象进行共情,从而提出不同符合用户心理的解决方案。最表象的不同点就在于,程序员完成需求代码化,优先考虑是否可以代码实现,过程中会有哪些限制条件;设计则更多考虑可用性和可视化,以一种更合理的状态传递相关的信息。设计师不只是基本需求的实现,同时要让用户有一种更优的体验,能够产生心理上的满足感和愉悦感。其实程序员思维和设计思维还是有共通点的,比如结构化思维的应用上,设计师需要以某种逻辑关系形成结构清晰的界面呈现给用户,大大增强页面的可读性和可理解性。同样的满足金字塔原理的代码,其可读性和可理解性也会极大的被增强。代码也是一种表达,很多人以为代码是写给机器执行的,实际上,代码是写给人读的,只是偶尔会被机器执行。四、程序员思维如何应用到设计中?1. 底层逻辑底层逻辑的应用其实是贯穿整个产品生命周期的,不论是需求阶段还是界面设计阶段亦或是开发实现和产品测试,都是基于底层业务逻辑去实现产品的。产品在交互设计上除了要符合业务逻辑,还需要符合开发实现逻辑。比如页面在进行数据交互时,接口的调用是同步还是异步,这也将影响到界面的交互形式。在开始设计前,我们就需要弄明白数据交互接口的调用方式,什么是同步什么是异步?这里我们先举个栗子。比如在正常工作中,我们需要和业务沟通需求。如果在会议室进行面对面沟通,当你抛出对需求的疑问后,需要业务当面给予你解答才算沟通结束。这种就是同步。如果在办公室用邮件的方式沟通,当你发出对需求的疑问后,不需要在邮箱界面等他回复,你可以关闭邮箱窗口去做其他的工作内容,不管多久,等他回复你邮件后,你都会即时收到邮箱消息提醒。这种就是异步。所以,和沟通一样,接口调用的方式分为同步调用和异步调用。同步调用是最常见的接口调用形式,在同步调用模式下,接口的调用方在一定时间范围内一直等待,直到被调用方返回执行结果。比如页面的加载,你需要停留在此页面等待加载完成才能继续后面的步骤。异步调用是接口调用方给被调用方发出指令,但不会愣在那等待结果,调用方会给被调用方提供一个回调接口,处理完成后,再调用回调接口返回结果。比如应用的更新升级下载,开始下载后我们可以将其置于后台下载,无需等待下载结果,同时可以去完成其他任务。我们无需去考虑通信的底层协议是什么,只单纯的考虑场景,电话沟通和页面加载就是同步,邮件沟通和升级下载就是异步。所以在实际交互设计过程中,我们需要找开发确认接口调用方式的底层逻辑,对于无需或者不能即时响应的工作考虑采用异步调用的交互设计方式。2. 抽象思维抽象思维看似与设计思维相冲突,一个是需要抽离高层次共性,考虑代码的可扩展性;一个是需要深入场景,精准的传递信息。实际上在设计中也有经常使用抽象思维,例如为了提高生产效率,我们会设计对应的组件库,提取常用的基础控件,普遍应用于各种产品。我认为大多数情况下,我们是将抽象思维逆向使用的。相同的组件,因为其功能是固定的,在大多数情况下都可以复用,但在一些特殊的场景,我们可以发散思维,设计出更多符合场景的组件样式,从而传达更具象的内容。比如简单的加载,比较大众的设计样式就是转菊花,这种加载可以应用到任何加载场景,常见得会让用户感觉很 low,没有任何辨识度。在实际设计中,我们是可以结合产品特性或品牌形象将其实例化或者内涵化,例如,B 站加载样式,融合了品牌 LOGO,将品牌基因也融入到简单的加载设计之中,加强用户对于产品的印象及帮助品牌传播。这种以抽象出来的类为出发点,逆向运用抽象思维,再结合自身的设计思维去发散,最后收敛得出一个有效的问题解决方案,也能很好的服务于我们的设计。3. 结构化思维人类很早以前就认识到,大脑会自动将发现的所有事物以某种秩序组织起来。基本上,大脑会认为同时发生的任何事物之间都存在某种联系,并且会将这些事物以某种逻辑模式组织起来。比如,通过对下图的观察,你可以看到什么?任何人,看到上面的 8 个方块,都会认为共有两组方块,每组 4 个。这是因为人类大脑天性所致,大脑会认为同时发生的任何事物之间都存在某种联系,并且会将事物按某种逻辑模式组织起来。这种“联系”指的是某种类似的共同点或所处的位置比较接近。这种将事物组成逻辑单元无疑具有很大的作用。我们更容易记住那些具有逻辑关系的东西,而遗忘那些散点的东西。其实以上的结构化思维方式也就是设计中的格式塔原理。如何在 B 端设计中应用格式塔 7 大原则?来看详细分析!B 端产品主要是 Web 端产品,空间大、操作多,内容相对复杂。阅读文章 > 为了更好的理解结构化思维的应用,我们可以以做简历设计为例,简历制作其实就是把个人相关的信息整理成结构化信息的过程。每个人的简历上大致会包含姓名、性别、民族、籍贯、出生年月、联系方式、电子邮箱、工作单位、工作时间、职位、工作职责、离职原因、毕业院校、学习时间、所学专业、获得证书等信息。这么多信息,如果不加整理的一一罗列,会显得非常繁杂,可读性非常差。我们可以将这些信息按一定的逻辑关系整理分组,读起来就会轻松很多。将信息进行结构化梳理后,会更清晰、更有条理。信息的传递效率也会大大提高。最后,无论是产品思维、设计思维,还是程序员思维,不应该成为职业的边界限制,亦或是不同职位间争议的起点。我们可以相互学习与了解不同的思维方式,共同更好地服务于产品。本篇来源:优设网原文地址:https://www.uisdc.com/programming-design
代码 程序员 项目 很多年前,当我还是一名计算机专业的大四学生时,整天上网浏览各类招聘信息,想找到一个合适的程序员实习岗位。除了实习岗位外,我偶尔也会点进一些“高级工程师”的招聘帖里。现在回想起那些帖子,抛开让人眼花缭乱的技术名词,我印象最深的就是常出现在第一行的岗位年限要求:“本职位要求 工作经验 5 年以上”。作为一只一天班都没上过的小菜鸟,这些年限要求在我眼里简直长到夸张。不过,望洋兴叹之余,我有时也会在心中暗暗憧憬一下:“五年工作经验的程序员,那该多厉害啊?写代码对于他们来说,是不是像吃饭一样简单?”时光荏苒,一晃十几年过去了。如今回头一望,自己也成了一名有着 14 年工作经验的光荣打工人。在软件开发行业摸爬滚打这些年后,我发现很多事情,与我在大四时所想象的大不相同,比方说:随着经验增长,编程并不会变简单太多,“像吃饭一样简单”只出现在梦里给许多“大项目”写代码不光没意思,还很危险,远不如在 LeetCode 上做一道算法题有趣只从技术角度思考问题,成不了好程序员,有些东西远比技术更重要细想起来,这类关于编程的感触还有许多。我整理了其中 8 条,写成了这篇文章。如果其中某些观点引起了你的共鸣,我会非常高兴。更多编程干货:学编程后,我做了这10个有毒的在线免费设计神器!(下)上篇的5个神器大受欢迎,人气极高。阅读文章 > 一、写代码很简单,但写好代码很难编程曾经是一项门槛很高的专业技能。从前,一个普通人想学编程,最常见的做法就是通过教材和书本学习。不过大部分编程专业书,十分艰深晦涩,对于初学者来说很不友好。因此不少人在尝到编程的乐趣前,就早早地半途而废。但如今,学编程正在变得越来越容易。学习不再像以前那样,只能硬啃书本,而是多了许多新途径。观看教学视频、参加 Codecademy[1] 的交互式课程,甚至直接在 CodeCombat[2] 通过玩游戏来学编程,每个人都能找到适合自己的学习方式。“妈,我真没在玩游戏,我在学编程呢!你看屏幕右边!”此外,编程语言也在变得越来越易用。经典的 C 和 Java 不再是大多数初学者的首选,许多更简单、更易上手的动态类型语言如今大受欢迎,与之相关的 IDE 等工具也变得越来越完善。这些因素进一步降低了编程的学习门槛。总而言之,编程早已褪去了它的神秘面纱,从只有少数人才能掌握的神秘技能,变成了一门人人皆可学习的普通手艺。但更低的学习门槛,更友好的编程语言,并不意味着人人都能写出一手好代码。如果你已经工作,参与过一些项目,那我很想问你一个问题:”你日常接触的这些项目的代码质量如何?是好代码多,还是烂代码多?”不知你会怎么回答,我先来说说我的答案。1. 好代码还是很少2010 年,我跳槽到了一家总部位于北京五道口的大型互联网公司。加入这家公司前,我只在十人规模的小公司待过,因此,我对新公司在各方面都有着很高的期待,尤其是软件质量方面。当时,我心里想的大概是这样:“这可是支撑了有着千万用户量的产品的大项目,代码质量跟之前那些比,肯定有质的飞跃吧!”等到在新公司工作了一周后,我才发现自己实在是错得离谱。所谓“大”项目的代码质量同我的预期相去甚远。打开 IDE,数百行的函数和神秘的数字字面量比比皆是,开发任何一个小需求都难如登天。后来,在待过更多公司,接触了更多软件项目后,我总结出一个道理:不论公司多大、项目多牛,在实际工作中遇见好代码,仍然是小概率事件。2. 好代码有哪些要素?话说回来,到底怎样的代码才算是好代码?在这方面,Martin Fowler 有一句话常被大家引用:“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”“任何傻瓜都能写出计算机能理解的代码。优秀程序员写人类能理解的代码。”我认为它可以作为评价好代码的原点:好代码一定是可读、易读,且容易理解的。写出好代码的第一原则,就是把人类读者放在第一位。除了可读性以外,评价代码好坏还有许多其他维度:贴合编程语言:是否使用了当前编程语言的推荐写法?语言特性和语法糖,使用程度是否恰到好处?易于修改:代码设计是否考虑了未来的需求变更,当变化发生时,代码是否容易随之修改?API 设计合理:API 设计是否合理,易于使用?好的 API 在简单场景下使用方便,在高级场景下又可以随需求扩展。性能够用:代码性能是否满足当前业务需求,同时为未来保留了一定提升空间?避免过度设计:代码是否存在过度设计、过早优化的毛病?…总而言之,对于任何层级的程序员来说,好代码都不是什么唾手可得的东西。要写出好代码,需要在许多维度上反复权衡、精心设计,最后再加以持续打磨。既然如此,假如想尽快掌握写代码这门手艺,有捷径吗?3. 写好代码的捷径在许多层面上,我认为编程和写作非常相似[3]。二者都是使用文本和符号来表达思想,只是方式略有不同。谈到写作,我想问一个关于作家的问题:“你听说过不读书的作家吗?你有没有听到过某位作家说,他从来不读其他人的作品,只读自己的东西?”。我猜答案应该是否定的吧。如果你去查阅相关资料,你会发现许多职业作家的日常生活,就是阅读和写作两件事在不断循环。他们每天会花大量时间阅读各类文字,然后再写作。同样是“文字工作者”,程序员们就很少重视阅读。但要想快速提升编程能力,阅读正是不可或缺的重要一环。除了日常工作接触到的项目以外,我们应该更多地阅读那些经典软件项目,从中学习 API 设计、模块架构和代码编写的技巧。不光代码和技术文档,最好再定期读一些计算机方面的专业书,保持阅读书籍的习惯。在这方面,我认为 Jeff Atwood 在 15 年前写的文章 "Programmers Don‘t Read Books -- But You Should(都说程序员不读书——但你应该读)"[4],如今读来仍不过时。提升编程能力的捷径,就藏在“阅读 编程”这个无尽循环里。“一个好的程序员应该做什么?”二、编程的精髓是“创造”在程序员的日常工作中,有很多事情会让人充满成就感,甚至情不自禁地感叹“编程真美好”。比方说,修复了一个极难定位的 Bug,用新算法将代码性能提升了一倍,等等。但在所有的这类事情当中,没有任何一件,能和“亲手创造出一件东西”相比。当你在编程时,创造新事物的机会实际上随处可见。因为并非只有发布一个新软件,才称得上是“创造”。写一个可复用的工具函数、设计一套清晰的数据模型,全都可以归入“创造”的范畴。身为程序员,保持对“创造”的热情至关重要。因为它可以帮我们:更高效地学习:学习一门新技术,最高效的方式就是用它开发一个真实项目,在创造的过程中学习,效果最好。有机会邂逅了不起的东西: 许多改变世界的开源软件,最初都是作者纯粹出于兴趣所创造,比如 Linus Torvalds 和 Linux,Guido van Rossum 和 Python。1989 年的圣诞假期,荷兰人 Guido van Rossum 敲下了 Python 语言的最初几行代码,Python 最初仅被期望作为 ABC 语言的继承者,但后来“吞噬”了全世界虽然“创造”好处多多,程序员们也有大把机会去做,但许多人常常缺少一种身为“创造者”的觉悟。就像那个广为流传的小故事所说:一位哲学家询问正在砌砖的工人,有人清楚地知道自己是在建造一座大教堂,有人却认为自己只是在砌砖。很多程序员正是“只见砖块,不见教堂”。将自己定位成创造者后,看待事物的方式就会发生天翻地覆的变化。举个例子,同样是给 API 增加报错提示文字,创造者们就能跳出“快速完成需求就好”的思维陷阱,向前一步,追问自己一些更重要的问题:“我想为用户创造什么样的产品体验?怎样的报错文字,更能帮助我达成该目标?”就像任何一个有用的编程模式一样,“创造者思维”也能成为你的职业生涯的一道巨大推进力。因此,现在就试着问自己一个问题吧——“我的下一份创造会是什么?”三、打造高效试错的环境至关重要我曾参与开发过一个互联网产品,它设计精美,功能丰富,每天都有大量用户使用。但就是这么一个从市场角度看颇为成功的产品,工程质量却非常糟糕。如果你打开它的后端项目,把所有目录翻个底朝天,都找不到任何一行单元测试代码,其他自动化测试流程也是无从谈起。而业务逻辑偏偏又十分复杂,最后,项目代码间的意料耦合多如牛毛,开发一个新特性,很容易把旧功能给搞挂。“在忙啥呢?” “试着修复我之前修一个问题时搞出来的问题,那问题是我之前解决另一个问题搞出来的,而那个问题又是我……”因此,项目每次发布时,开发和产品同学全都得严阵以待,氛围十分紧张。整个发布过程也很刺激,紧急回滚时有发生。一个人在这样的环境中工作,技术成长抛开不谈,心理素质肯定能得到极大锻炼。编程原本是一件充满乐趣的工作,但为这样的项目编程,乐趣根本无从谈起。究竟是什么夺走了编程的乐趣?1. 理想的编程体验“刷题”LeetCode[5] 是一个著名的编程学习网站,上面提供了许多覆盖各个难度的编程题,大部分与算法相关。用户可以选择自己感兴趣的题目,直接在浏览器上编写代码(支持十几种编程语言)并执行。如果通过了全部的测试用例,则算作解答成功。在 LeetCode 上做题在 LeetCode 刷题很像在玩游戏,富有挑战性,同时也很有趣。整个做题过程,实际完美展现了一种理想化的编程体验:关注点分离:每道题目都是一个独立个体,同一时间内,开发者可以完全沉浸在一道题目中;快速获得精准反馈:开发者每次调整代码后,能通过自动化测试快速获得结果反馈;零成本试错:写出的代码语法有错误、逻辑有问题,没有任何不良后果,心理负担小。不过,屏幕前的你很可能觉得我在说些废话。“不然呢?解算法题、写小脚本,不就是这样的体验吗?有啥特别值得说的?”你很可能会继续补充道,“你知道我们公司的项目有多复杂吗?规模超大,模块巨多,你懂我意思吗?每天服务 万人,光数据库就好几套,消息队列都有三种,开发起来当然要麻烦一点咯!”确实,全世界的软件千差万别,开发起来不可能都像在 LeetCode 上刷题一样轻松愉快。但这并不意味着,我们不应该努力改善自己身处的编程环境,哪怕只有一点点。要通过改善环境来提升编程体验,可用的理念和工具包括:模块化思想:妥善设计项目中的每一个模块,降低耦合,提升正交性设计原则:微观层面上,应用那些经典的设计原则和模式,比如“SOLID”原则自动化测试:编写规范的单元测试,必要时使用 Mock 技术,用自动化测试覆盖业务关键路径缩短反馈回路:切换编译速度更快的工具,优化单测性能,竭尽全力缩短从“改完代码”到“获得反馈”的等待时间微服务架构:必要时,将大单体拆分为多个职责各异的微服务,分散复杂度……关注编程环境,刻意创造出允许高效试错的“代码乐园”,让工作像刷题一样轻松愉快。是经验丰富的程序员能为自身团队做出的最好贡献之一。四、避开代码完美主义陷阱在代码质量上精益求精是好事,但也要注意别掉进完美主义的陷阱。因为编程不是艺术创作,不鼓励人们无限度地追求极致。作家大可花上数年打磨一本传世之作,但程序员在代码上钻牛角尖就很有问题。世间没有完美的代码。大多数时候,你的代码只要能满足当前需求,又为未来扩展留了一些空间就够了。有那么几次,我在简历上看到候选人给自己打着“代码强迫症”标签。隔着屏幕,我虽能感受到 TA 对代码质量的那份重视,但在我心底,其实更期望 TA 早已将完美主义陷阱远远甩在了后头。五、技术很重要,但“人”也许更重要在软件开发领域,“单一职责原则”(全称为 Single responsibility principle,后简称为 SRP)是一条非常著名的设计原则。它的定义很简单,一句话就可以概括:“每个软件模块应该只有一个被修改的理由”。单一职责原则:能做到,并不意味着你就该这么做要掌握 SRP 原则,关键在于搞清楚“被修改的理由”为何物。很显然,程序是没有生命的,它自身不能也不需要主动去改变。任何修改程序的理由,都来自与之相关的人,人是导致修改的“罪魁祸首”。举个简单的例子。看看下面这两个类,其中哪一个违反了 SRP 原则?一个字典数据类,支持两类操作:存数据、取数据;一个员工资料类,支持两类操作:更新个人信息、渲染一张用户资料卡片图。在大多数人眼里,第一个例子没问题,但第二个例子却明显违反了 SRP 原则。要得出该结论,好像无需任何严格的分析和证明,运用一丁点直觉即可。但假如做一些正经分析,第二个例子的可疑之处,在于能为其轻松找出两个不同的修改理由:管理员认为资料中的“个人电话”字段不能有非法号码,需增加简单的校验逻辑某员工认为资料卡片图上的“名字”部分太小,希望加大字体”It is people who request changes. And you don’t want to confuse those people, or yourself, by mixing together the code that many different people care about for different reasons.” ——“The Single Responsibility Principle”“是人在要求软件变更。你绝不想把那些不同人出于不同原因所关心的代码混在一起,这样只会把他们和你自己搞糊涂。”——“单一职责原则”理解 SRP 原则的关键,在于先理解人以及人在软件开发中所扮演的角色。再举一个例子。微服务架构是近些年很火的一个技术话题。但许多人在讨论它时,往往只关注技术本身,却忽视了微服务架构与人之间的关系。将微服务架构风格与其他东西区分开的关键,在于将大单体拆分为独立的微服务后,不同模块间的边界可以变得更清晰。跟数百人的团队一同维护着一个大单体比起来,许多小组织各自维护着独立的微服务,明显拥有更高的运作效率。如果缺少了特定的组织规模(也就是“人”)作为前提,空谈微服务的各种技术优势和那些花活,纯属本末倒置。技术当然很重要。身为技术人员,那一张张瑰丽的架构图和独具匠心的代码细节,天然吸引着我们的注意力。但是,也请千万不要对软件开发里的另一个重要因素“人”视而不见。必要时,转换一下看事情的角度(从“技术”转向“人”),那样对你大有裨益。六、求知若渴是好事,但也要注意方法如今人人都在说“终身学习”,而程序员是一个尤其需要终身学习的职业。因为计算机技术的迭代更新非常快,某个三年前流行的框架或编程语言,很可能一个月前已经过时。一分钟之内会发生什么事情?Netflix 观看时间增长 70,000 小时;Snapchat 上有三百万视频被观看;Google 新增两百四十万次搜索;一个 JS 新框架被发明(这条不是真的 )要在工作中表现得游刃有余,程序员们需要学习的东西非常多,涵盖各个层面。拿我比较熟悉的后端领域举例,一位合格的后端工程师至少需要掌握以下这些:一种或多种后端编程语言 / MySQL 等关系数据库 / Redis 等常见存储组件 / 设计模式 / 用户体验 / 软件工程 / 编译原理 / 操作系统 / 网络基础 / 分布式系统 / …虽然要学很多,但据我观察,大部分程序员其实都挺爱学习(至少不排斥),因此心态不是问题。不过有的时候,光有“求知若渴”的心态并不够,学习时,我们尤其需要关注“性价比”。1. 关注学习性价比下面这张图,展示了学习成效和投入之间的关系。学习成效与投入关系图,横轴为学习投入,纵轴为学习成效从图中可以看到,在学习的初级阶段,投入较少时,所获得成效增长飞快。但当成效超过某个阈值后,之后再想继续提升,所需要的学习投入就会呈指数级增长。正因如此,我建议你在学习任何一项新事物时,先在脑海中想清楚一个问题:“我应该在上图中的哪个位置停下来?”,而不是闷头猛学。知识的海洋浩瀚无边,有些东西需要我们成年累月的持续学习,不断精进。也有些东西,蜻蜓点水般学到一些皮毛已绰绰有余。准确判断并分配自己有限的学习精力,甚至比努力学习本身更重要。2. 挑选合适的学习资料有了学习目标后,下一步就是寻找合适的学习资料。在这方面,我想分享一次自己的失败经历。有段时间,我突然对产品交互设计产生了浓厚的兴趣,认为自己应该在这方面有所精进。于是,我精心挑选了一本领域内非常经典的专业书:《About Face 4: 交互设计精髓》[6],将其买回家中,满怀信心地认为自己的交互设计能力可以迅速获得提升。但事与愿违,当我捧着那本经典著作时,发现自己连第一章都无法顺利读完——那句老话说的没错:“隔行如隔山”。从这次失败中,我总结出了一点经验。那就是学习某项新东西时,我们最好挑选那些更易读,更适合“门外汉”的学习资料,不要“眼睛大,嘴巴小”,只知道奔着最经典、最权威的资料而去。回顾之前的经历,我觉得以下几本书非常适合门外汉学习使用,性价比极高:《写给大家看的设计书》[7]:设计相关《点石成金》[8]:Web 用户体验相关《鸟哥的 Linux 私房菜》[9]:Linux 系统相关也许每个人的内心,都想成为一个博学的人,无所不知,无所不晓。但可供分配的时间的精力总是有限,我们不能,也不需要在所有领域都成为专家。七、越早开始写单元测试越好我非常非常喜欢单元测试,我认为写单测这件事,对我的编程生涯影响极大。夸张点说,如果以“开始写单元测试”作为分界线,把我的职业生涯分割成两段,后面那段远比前面那段精彩得多。写单测的好处很多,比如单测可以驱动你改善代码的设计、可以作为代码的一种文档,等等。此外,完善的单元测试还是构建前面提到的“高效犯错的环境”的关键。我已经写过几篇关于单测的文章,比如《有关单元测试的 5 个建议》[10]、《游戏“蔚蓝山”教我的编程道理》[11]。所以在这儿,我不打算再重复一遍。只说一句:如果到目前为止,你从未试过写单元测试,或从没重视过测试,我建议你从明天就开始写起来。一般情况下我不测试我的代码,但假如测的话,我在生产环境测八、程序员最大的敌人是什么?在大多数程序员段子里,产品经理经常作为反派角色出现。他们口中的项目需求总是变个不停,一天冒出一个新想法,搞得程序员苦不堪言。客户每天都在不停修改需求,所以,我们决定在下次发布前,把这些需求“冻结”起来在这些段子的烘托下,不断修改需求的产品经理,仿佛真成了程序员们最大的仇敌。似乎只要产品不乱改需求,大家的工作环境马上就会成为乌托邦。虽然偶尔吐槽一两句产品经理很有意思,但我还是想一本正经的说一句:产品经理不是敌人。因为从某种角度来说,软件生来就是准备被修改的(不然你猜,软件为什么叫“软”件?)。这样看来,开发软件和修建房子完全不同。因为没人会在建好一栋大楼后说:“让我们把它推倒重建一遍吧!一样的楼,但是用的钢筋和水泥比之前少 30%!”所以,产品经理以及不稳定的需求不是程序员的敌人。并且,能否写出易于修改、适配变化的代码,是区分普通程序员和优秀程序员的重要标准之一。那么,程序员们最大的敌人又是什么呢?1. 复杂度是最大的敌人就像《代码大全 2》中所说:软件开发的核心问题是管理复杂度。失控的复杂度就是程序员最大的敌人。来看看那些导致项目复杂度不断增长的要素:不断增加的新功能: 更多的功能等于更多的代码,更多的代码通常意味着更高的复杂度对高可用的需求: 为了实现高可用,消息队列等额外的技术组件和代码被引入对高性能的需求: 为了提升性能,缓存和相关模块代码被引入,部分模块被拆分后,换成高性能语言重写一再被推迟的重构:因项目排期过于紧张,迫在眉睫的重构被一再推迟,技术债越积越多忽视自动化测试: 没人写单元测试,也没人关心测试…终有一天,当项目的复杂度增长到一定程度后,空中会传来一声巨响。“咚!”,一个大家不愿改、不敢改的“大坑”凭空出现在了所有人的 IDE 中。猜猜看,究竟是谁挖下了这个坑?那些在降低复杂度上投入时间的团队,所负责的软件项目更容易成功2. 减缓复杂度增长的过程虽然复杂度总是会不可避免地持续增长,但有许多实践可以减缓该过程。如果每个人都能做到以下这些事,复杂度就有可能被长期控制在合理范围内:精通当前编程语言与工具,写整洁的代码使用合适的设计模式和编程模式对重复代码零容忍,抽象库和框架适当运用整洁架构、领域驱动设计思想编写详尽的文档和注释编写规范有效的单元测试分离那些变动的与不变的…要求看上去很多,但总结起来,核心其实就是一句话:写更好的代码。写在最后2020 年,我在小组内做了一个分享,当时的 PPT 标题是《编程十年后的十个感触》。将资料分享在公司内网后,有位同事看到,评论说光看 PPT 不过瘾,希望我能将其扩展成一篇文章,我回复说没问题。如今 3 年过去了,我总算是兑现了自己的承诺。当年准备分享材料时,我做完整个 PPT,最后一页实在不知道该放些啥。于是灵机一动,搞了个纯白色的背景,中间打了一行黑体大字:“十年很短,编程很难”。如今,第二个十年也已快行至中途,而这句话的后半部分好像对我仍然适用——长进不大,继续加油 。原文链接:https://www.piglei.com/articles/programming-is-still-hard-after-14-years/欢迎关注作者微信公众号:「piglei」本篇来源:优设网原文地址:https://www.uisdc.com/8-programming-experience