精华内容
下载资源
问答
  • 在软件项目中,需求分析是最开始工作,同时也是最重要的工作。需求分析如果做得不够详细或者是偏离用户需求或者是存在缺陷话,往往会给项目带来灭绝性的灾难,不重视需求过程项目团队将自食其果。因此,如何保证...

    在软件项目中,需求分析是最开始的工作,同时也是最重要的工作。需求分析如果做得不够详细或者是偏离用户需求或者是存在缺陷的话,往往会给项目带来灭绝性的灾难,不重视需求过程的项目团队将自食其果。因此,如何保证需求分析的正确、准确性,成了决定软件项目成败的关键因素。

    需求偏差原因:

    • 在实际的项目过程中,需求阶段往往是由一两位需求分析人员与用户沟通用户需求,然后根据自己的理解输出软件需求说明书及软件原型。

    • 经验再丰富的需求分析人员也可能犯错,所谓智者千虑,必有一失,这是永远不变的客观规律。

    • 受需求分析人员的理解及用户的表达等因素的影响,需求在传递过程中往往存在很大偏差。

    • 需求分析人员输出的需求分析说明书,到设计人员、编码人员、测试人员那里往往又会有不同的理解。

    软件需求分析说明书的正确性必须得到彻底的验证,利益相关方必须彻底理解需求,并达成一致。要达成这一目标、降低需求风险,需求评审是一个行之有效的方法。

    软件需求说明书不应该只是用户意愿的表达,而应该是从软件层面上对用户需求的总结。

    评审不是走过场,

    • 目前,很多小型软件企业在需求阶段,往往是需求人员写完需求后再跟用户沟通一下,就直接进入设计开发阶段了,设计、编码、测试人员前期没有参与进来,根本没有进行需求评审。

    • 也有不少企业的需求评审存在“走过场”的情况,其他人员根本不关心软件需求,认为软件需求就是需求分析人员的事情,他们怎么写大家怎么做就可以了,在提需求异常时简单找几个错别字提一下应付了事,没有提出有效的需求异常。

    • 也有的时候,在需求评审会议中,大家的关注点常常会不知不觉的转向设计,结果需求评审会议成了设计讨论会议,大家想得最多的是需求如何实现,而不是需求文档本身有无问题。

    评审开始

    1ee67b104c7bd52a894fbe185e804fda.png

    评审人员选择

        需求评审涉及到各层次人员,在进行评审员选择时,一定要将各层次人员都囊括进来,他们可能有用户、需求分析人员、产品经理、项目经理、架构师、概要设计人员、详细设计人员、编码人员、测试人员、质量保证人员等等

    • 用户在进行需求评审时,关注点更多在于他们所要求的功能是否在软件需求说明书中都囊括进来了;

    • 架构师及概要设计人员更多关注的是在现有的技术条件下,是否能够实现需求中的要求,如果无法实现需求或者代价太大,可能就要需求人员与用户沟通更改需求;

    • 编码人员可能更多关注于某些细节,例如界面元素等;

    • 测试人员主要关注是否所有的需求都是可测试的;

    • 质量保证人员关注点在于输出物是否符合规范。

    各层次人员充分参与,便于他们理解需求,通过需求评审,达成一致意见,不至于需求在不同环节因理解不同而出现偏差。

    因为各层次人员的立场不同,对同一个问题的看法是不相同的,有些观点是和系统的目标有关系的,有些是关系不大的,不同的观点可能形成互补的关系。如果漏掉某一层次的人员,可能会漏掉很重要的需求。

    正式评审与非正式评审结合

      正式评审时指通过开评审会的方式,将需求涉及到的人员集合在一起,并定义好参与评审人员的角色和职责,对需求进行正规的会议评审。很多时候,因为需求内容太多,正式的评审会议中不可能将每一个细节都涉及到,评审员也有一个理解需求的过程,在短短的会议中不可能发现太多问题。

    因此,需要与非正式评审相结合,在评审会之前可以先开会对大家进行需求讲解,然后把需求通过邮件等方式发送给相关人员,留几天时间,以便相关人员仔细研究,记录异常,在正式的评审会上讨论。

    把握需求评审的关键点

      (1)注意对软件需求说明书的正确性进行评审。需求规格说明的正确性通常可以从如下方面得以体现:

      ①是否有需求与其他需求相互冲突或者重复?  ②是否清晰、简洁、无二义地表达了每个需求(“清晰”是让人能够读懂;“简洁”是让人愿意去读;“无二义”决定“读”的效果,是让大家对需求描述的理解能够达成一致)?  ③是否每个需求都通过了演示、测试、评审,分析是否得到了验证?  ④是否每个需求都在项目的范围内?  ⑤是否每个需求都没有内容和语法上的错误?  ⑥在现有的资源内,是否能实现所有的需求?  ⑦每一条特定的错误信息,是否都是唯一的和具有含义的?

      (2)注意对软件需求说明书的实践性进行评审。所谓实践性是指需求本身是否来源于目前企业的相关业务规则和文件制度,而非源于分析师们经验主义的臆测。实践性是判断需求规格说明是不是理论联系实践、密切和用户联系的一个关键性指标。

      (3)注意对需求规格说明书的完整性进行评审。可由下面的问题清单来评审需求说明书是否“完整”:

      ①编写的所有需求,其详细程度是否一致和合适?  ②需求是否能为设计提供足够的基础?  ③所有对其他需求的内部引用是否正确?  ④是否包含了每个需求的实现优先级?  ⑤是否定义了功能说明的内在算法?       ⑥是否包含了所有已知的客户需求或系统需求?       ⑦是否遗漏了必要的信息?       ⑧是否对所有预期的错误条件所产生的系统行为都编制了文档?

    需求说明的完整性主要体现在需求说明的详细程度上,怎样判断该需求的描述是否详细呢?笔者认为需求需要精化,而不是仅仅提出精化功能、对象要考虑涉众参与者、做些什么、需要什么数据信息、受什么业务规则和条件限制、系统会有什么响应等。

      (4)注意对需求方案的可行性和成本预算进行评审。

      (5)注意对需求的质量属性进行评审。评审需求规格需要说明是否合理地确定了所有的性能目标,是否合理地确定了安全性方面要考虑到的问题。

      (6)注意对需求的可实施性进行评审:

      ①是否对每个需求都设置了唯一性并且可以正确地识别它?  ②是否每个功能需求都可以跟踪到高层需求?

    需求必须可以测试,每个需求在特定的输入条件下应当能给出已知的输出结果,同时,需求应当层次分明,需要把单个需求下面的相关需求综合在一起形成一组需求功能。需求的可实施性除了可跟踪性还包括可测试性,事实上,分析人员和测试人员在编写代码以前把需求模型,分析模型和测试用例综合起来通盘考虑,检查出遗漏的、错误的和不必要的需求,软件需求在概念上的测试是一种很必要的技术,它可以在项目早期阶段发现需求的歧义和错误。

      (7)注意对需求包含的用例文档进行评审。用例是参与者对系统和参与者的交互过程所达成的一种契约。需求说明书基于用例的分析方法是也是当前较为流行的需求开发方式。用例文档作为需求重要的成果性文档也是需求评审主体之所在。

      需求评审确认的重点是对关键用户的最常用和最重要的用例进行深入和细致的评审,首先要通过测试用例的主干过程。而是否撰写有效的用例则要从以下方面着手评审:用例的目标或价值度量是否明确?用例是否是独立的分散任务?

      是否明确说明可用用例会给哪些参与者带来用处?编写用例的详细程度是否恰当?是否有不必要的设计和实现细节?所有预期的分支过程是否都编写了文档说明?所有预估的异常过程是否都编写了文档说明?是否存在一些普通的动作序列可以分解成独立的用例?

      每个路径的步骤是否都清晰明了,无歧义而且完整?用例中的每个参与者和步骤是否都与所执行的任务有关?用例中定义的每个可选路径是否都可行和可验证?用例的前置条件和后置条件是否合理?分析师必须确认用例的前置条件和后置条件准确界定了用例的边界范围,区分了用例和用例之间的界限。

    需求审查结束的标准为

    • 已经明确阐述了审查员提出的所有问题、

    • 已经正确修改了文档、

    • 修订过的文档已经进行了语法检查、

    • 所有TBD问题都已经解决、

    • 文档归档

     在需求评审后,需要根据评审人员提出的问题进行评价,以确定哪些问题是必须纠正的,哪些可以不纠正,并给出充分的客观的理由与证据。

      当确定需要纠正的问题后,要形成书面的需求变更的申请,进入需求变更的管理流程,并确保变更的执行,在变更完成后,要进行复审。切忌评审完毕后,没有对问题进行跟踪,而无法保证评审结果的落实,使前期的评审努力付之东流。

    展开全文
  • 侯震宇:我们是做代码评审的,但不会对所有代码做评审。代码是可以分级的,一方面从代码本身的重要性来分,另一方面从代码编写者的熟练度来分。代码评审在我们内部叫Code Review,其有两个目的。第一也是最主要的...
     侯震宇:我们是做代码评审的,但不会对所有代码做评审。代码是可以分级的,一方面从代码本身的重要性来分,另一方面从代码编写者的熟练度来分。代码评审在我们内部叫Code Review,其有两个目的。第一也是最主要的目的是检查代码的质量,第二是学习一些优秀的代码,大家关心的可能是第一点。对入职时间不长的新人,需要监控其代码质量,纠正其在编写代码中的不良习惯,并使他们逐步融入我们统一的编程风格中。对于这种情况,我们一般有安排专人Review新人的代码。需要指出的是,不能指望Code Review发现所有代码层面的问题,它只能解决一些表面问题,而很难发现代码逻辑上的问题。代码逻辑上的问题需要通过后期的测试来解决。这里说的表面问题主要指缺乏注释、大量使用全局变量以及明显的一些可能引发Bug的问题(如在不知道字符串长度的情况下使用Copy等),这其中包括程序员编码的基本素质和编程风格两个因素。编码的素质可以通过训练和逐步积累提高,但编程风格不容易改变,只能进行约束。
    

    所以说Code Review只是发现问题的一种手段,但不是解决问题的方法。提高代码质量我觉得分为三个层次:第一,通过框架约束;第二,工具检查;第三,Code Review检查错误。我们逐个层面来看:

    编程框架的约束。减少程序员代码中的Bug的最好方法,就是少写代码。我们会有专人编写适合绝大多数业务的编程框架,将我们的程序员从编写没有营养、易出错的代码工作中解放出来。程序员只需要写一些配置或描述,就可以由框架生成可运行的代码框架。这既提高了程序员的工作效率,使程序员关注在业务逻辑实现上,也由于框架的约束使程序形成了统一的风格和代码结构。同时由于是自动生成的框架代码,这部分经过严格的测试,可以确保是高质量的代码,大大降低Bug数。

    编程规范的工具检查。肉眼Review代码的效率是很低的。结合我们自己的编程规范编写的工具,可以像编译检查一样检查出大批不符合规范的代码缺陷。这些缺陷如代码缺乏注释、参数未被使用、函数没有返回值等。代码检查工具执行后会形成报告,指出缺陷的位置和一定的统计信息,这对于程序员提高自己的代码水平是很有帮助的。将工具检查结果与代码准入的流程相结合,可以大批过滤掉提交代码的低水平缺陷或Bug。

    最后才是Code Review,再往后就到了测试阶段了。

    总之,代码评审对于提高代码质量是很有帮助的,但只做代码评审是不够的或者说意义不大。如何最大限度地提高代码质量减少缺陷,是每个工程师和架构师都需要考虑的问题,涉及诸多方面,这都需要我们去关注。

    展开全文
  • 浅谈软件工程中的代码评审

    千次阅读 2018-10-14 17:23:39
    代码评审这个词相信很多做开发的同学一定不会陌生,线上故障回顾总结有代码评审和单元测试总能够被高频率的提及并作为主要的整改意见,可见代码评审对于软件工程质量保证的重要性。相对于单元测试,代码评审的普及率...

    代码评审这个词相信很多做开发的同学一定不会陌生,线上故障回顾总结有代码评审和单元测试总能够被高频率的提及并作为主要的整改意见,可见代码评审对于软件工程质量保证的重要性。相对于单元测试,代码评审的普及率是相对较少,相信主要原因是代码评审的执行难度高,灵活性大,评审的方法和规则难于标准化等原因,要做好代码评审往往也困难许多,这里除了涉及到具体的技术知识和业务知识,还需要评审双方的沟通能力,表达能力,个人态度以及团队氛围等多种个人软件技能或者团队开放度。

    什么是代码评审

    根据维基百科的定义,代码评审是软件质量保证一种活动,由一个或者多个人对一个程序的部分或者全部源代码进阅读理解。一般来说分为作者和评审者两种角色,作者方提供代码逻辑的介绍和代码,评审者则对提供的代码基于设计,功能性和非功能性等方面认知进行阅读并提出问题。常见的评审组织形式是有同行评审(Peer Review)和小组检查 (Team Inspection)两种方式。

    代码评审目的

    维基百科中提到通过代码的评审发现潜在的问题是代码评审主要的目的。这是不可否认的当时提出代码审查的初衷,但从我个人的实践中发现,分享和表达是代码评审过程最主要的收获。通过代码评审可能无法发现更多的明显的问题,但是一定可以通过评审过程学习和交流发现代码中存在的优点和缺点,让新同学了解业务,让老同学知道可能有更优的设计和用法。同时让同事们在评审中交流表达自己的观点,让同学们有更多的开口机会。
    image

    根据Google 工程团队执行代码评审活动后发现,除了捕捉bug外,还对5大无形收益。

    • 代码评审促进团队和个人开放度
    • 代码评审提升团队交付标准
    • 代码评审激励团队协作
    • 代码评审保持安全至上
    • 代码评审构建社会认可
    什么时候做代码评审

    代码评审最重要的一点是非常灵活,无固定形式,随时随地都可以发起。根据Github和Apache一些开源项目的代码评审实践,往往是将PR合并到主干时进行评审并作为是否合并到Master分支的一个准入条件。对于团队办公集中且人员比较固定的组织,可以基于commit进行评审,那么对于每次需要评审的工作不会太高,时效性也容易把握。

    如何执行代码评审
    作者 (Author)
    • 确定待评审的代码范围

    根据SamrtBear在思科的一个系统小组的研究,一个开发人员一次评审的代码在200-400之间,审查超过400行代码后效率和发现均呈下降趋势。如下图:
    image

    同时,一个小时审查的代码行数应该少于500行,超过500行后效率呈下降趋势。
    image

    • 简单的描述代码业务逻辑以及主要的业务流程
    • 开放的心态接受评审的问题或者建议
    评审者(Reviewer)
    • 准备一个检查列表
    • 了解业务逻辑和主要流程
    • 准备好一些问题,对于不确定或者不明白,尽量以问题形式跟作者沟通,而非质疑。
    • 准备一些解决方案。在提出问题时候,同时思考更好的方法或者解决方案是什么?你的方法好在什么地方?
    代码评审的关注点
    • 功能性 - 功能完整,是否严格按照产品说明书实现产品的所需的功能点
    • 可读性 - 代码易读易懂,其它人能够轻松从代码中读逻辑和设计思想,命名是一个学问。
    • 可测性 - 代码能够轻松被单元测试覆盖,一般来说无法被单元测试覆盖的代码不是一个好代码
    • 可维护性 - 代码运行期间日志输出完整,运维人员或者其它人员可以从日志中了解应用的运行逻辑和状态。
    • 性能 - 天下武功唯快不破,确保代码在可度量的数据量级下面保持一个稳定的性能表现。代码是否存在性能问题,预计峰值流量能到多少。
    • 多线程,并发和锁 - 在并发或者多线程情况下,代码执行结果是否有问题。过去几个月中我们有一个应用是以Shell的方式启动任务,每一个作业一个进程。由于这种方式带来的资源利用率较低,打算改成多个作业运行在一个进程中(容器)以节省系统资源, 上线后发在存在多处线程不安全的问题,实例变量被污染导致线上问题。
    • 安全性 目前虽然有很多的扫描工具可以帮助发现代码安全的问题,但更专业的开发人员在写代码就已经注意这个问题,避免基本的SQL注入,XSS跨域等问题。有兴趣的同学可以参考OWASP CODE REVIEW GUIDE
    代码评审中注意事项
    • 代码评审不仅是技术,也社会学。双方沟通表达能力决定代码评审的效率和有效性。评审者需要注意问题的方式或者语气,就事论事,不上升到精神和思想层面。而作者则需秉承一切问题都可探讨或有更好的方案的想法吸收理解他人的想法,即使评审提出不合适的问题,那么你让队友知道一个正确的方法仍然是团队和组织的收获。
    • 代码评审不应太过于关注代码风格,代码风格的检查完全可以通过IDE或者扫描工具SONARCube集成CheckStyle, PMD,FINDBUG实现。
    代码评审的参考书
    1. 大厂的Java编码标准,如唯品会Java编码规范阿里Java编码规范

    2. 设计模式: Design Patterns, Elements of Reusable Object-Oriented Software

    3. 代码整洁之道: clean code-代码整洁之道

    4. 高性能Java开发: Effective Java, Third Edition

    5. 重构: Refactoring_improving_the_design_of_existing_code

    6. 代码大全: code-complete-2nd-edition-v413hav.pdf

    参考文档
    关于作者

    王云 - 唯品会财务研发微胖中年男,常年关注架构设计,高性能应用设计,软件工程,团队管理等领域。

    展开全文
  • 编写代码的规范可以看出 本文由Matt Burnett , Simon Codrington和Nilson Jacques进行同行评审。 感谢所有SitePoint同行评审员使SitePoint内容达到最佳状态! 您是否曾经在一次运行中完成过一个项目,而无需...

    编写代码的规范性可以看出

    本文由Matt BurnettSimon CodringtonNilson Jacques进行同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!

    您是否曾经在一次运行中完成过一个项目,而无需再次查看代码? 我也不是。在处理较旧的项目时,您可能想花费很少甚至没有时间弄清楚代码是如何工作的。 必须保持可读的代码,以保持产品的可维护性,并使您自己以及您的同事或合作者感到高兴。

    JS1k竞赛中可以找到无法理解的代码的夸大示例, 竞赛的目标是编写具有1024个字符或更少字符的最佳JavaScript应用程序,以及仅使用六个不同字符的深奥编程风格JSF * ck (顺便说一下,NSFW)编写JavaScript代码。 在这两个站点上查看代码都将使您感到疑惑。 想象一下编写此类代码并在几个月后尝试修复错误。

    如果您定期浏览互联网或构建界面,您可能会知道,退出一个看起来又大又小的大型表单要容易一些。 关于代码也可以这样说。 当被认为更易于阅读和工作时,您可能会喜欢更多地工作。 至少可以避免您无奈地扔掉计算机。

    在本文中,我将介绍一些技巧和窍门,以使您的代码更具可读性,并避免一些陷阱。

    代码分割

    坚持使用形式比喻,形式有时会分成几部分,从而使它们看起来没有障碍。 使用代码也可以这样做。 通过将其分成几部分,读者可以跳过与自己相关的内容,而不必在丛林中耕作。

    跨文件

    多年以来,我们一直在为网络优化事物。 JavaScript文件也不例外。 考虑到最小化和HTTP / 2之前的版本 ,我们通过将脚本合并为一个脚本来保存HTTP请求。 今天,我们可以按需要工作,并有一个任务运行器(例如GulpGrunt)来处理文件。 可以肯定地说,我们可以按照自己喜欢的方式进行编程,而将优化(例如并置)留给工具。

    // Load user data from API
    var getUsersRequest = new XMLHttpRequest();
    getUsersRequest.open('GET', '/api/users', true);
    getUsersRequest.addEventListener('load', function() {
        // Do something with users
    });
    
    getUsersRequest.send();
    
    //---------------------------------------------------
    // Different functionality starts here. Perhaps
    // this is an opportunity to split into files.
    //---------------------------------------------------
    
    // Load post data from API
    var getPostsRequest = new XMLHttpRequest();
    getPostsRequest.open('GET', '/api/posts', true);
    getPostsRequest.addEventListener('load', function() {
        // Do something with posts
    });
    
    getPostsRequest.send();

    功能

    函数使我们可以创建可重用的代码块。 通常,函数的内容是缩进的,从而可以轻松查看函数的开始和结束位置。 一个好习惯是使函数保持很小(10行或更少)。 正确命名函数后,也很容易理解调用函数时发生的情况。 稍后我们将讨论命名约定。

    // Load user data from API
    function getUsers(callback) {
        var getUsersRequest = new XMLHttpRequest();
        getUsersRequest.open('GET', '/api/users', true);
        getUsersRequest.addEventListener('load', function() {
            callback(JSON.parse(getUsersRequest.responseText));
        });
    
        getUsersRequest.send();
    }
    
    // Load post data from API
    function getPosts(callback) {
        var getPostsRequest = new XMLHttpRequest();
        getPostsRequest.open('GET', '/api/posts', true);
        getPostsRequest.addEventListener('load', function() {
            callback(JSON.parse(getPostsRequest.responseText));
        });
    
        getPostsRequest.send();
    }
    
    // Because of proper naming, it’s easy to understand this code 
    // without reading the actual functions
    getUsers(function(users) {
        // Do something with users
    });
    getPosts(function(posts) {
        // Do something with posts
    });

    我们可以简化上面的代码。 请注意,两个功能几乎是一样的吗? 我们可以应用“ 不要重复自己做 (DRY)”原则。 这样可以防止混乱。

    function fetchJson(url, callback) {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.addEventListener('load', function() {
            callback(JSON.parse(request.responseText));
        });
    
        request.send();
    }
    
    // The below code is still easy to understand 
    // without reading the above function
    fetchJson('/api/users', function(users) {
        // Do something with users
    });
    fetchJson('/api/posts', function(posts) {
        // Do something with posts
    });

    如果我们想通过POST请求创建一个新用户怎么办? 此时,一种选择是向该函数添加可选参数,向该函数引入新的逻辑,从而使其对于一个函数而言过于复杂。 另一种选择是专门为POST请求创建一个新功能,这将导致重复的代码。

    通过面向对象编程 ,我们可以充分利用两者,从而使我们能够创建可配置的一次性对象,同时保持其可维护性。

    注意 :如果您需要专门针对面向对象JavaScript的入门知识,建议您观看以下视频: 面向对象JavaScript权威指南

    面向对象编程

    考虑对象(通常称为类),它们是上下文感知的功能簇。 一个对象非常适合放在专用文件中。 在我们的例子中,我们可以为XMLHttpRequest构建一个基本的包装器。

    HttpRequest.js

    function HttpRequest(url) {
        this.request = new XMLHttpRequest();
    
        this.body = undefined;
        this.method = HttpRequest.METHOD_GET;
        this.url = url;
    
        this.responseParser = undefined;
    }
    
    HttpRequest.METHOD_GET = 'GET';
    HttpRequest.METHOD_POST = 'POST';
    
    HttpRequest.prototype.setMethod = function(method) {
        this.method = method;
        return this;
    };
    
    HttpRequest.prototype.setBody = function(body) {
        if (typeof body === 'object') {
            body = JSON.stringify(body);
        }
    
        this.body = body;
        return this;
    };
    
    HttpRequest.prototype.setResponseParser = function(responseParser) {
        if (typeof responseParser !== 'function') return;
    
        this.responseParser = responseParser;
        return this;
    };
    
    HttpRequest.prototype.send = function(callback) {
        this.request.addEventListener('load', function() {
            if (this.responseParser) {
                callback(this.responseParser(this.request.responseText));
            } else {
                callback(this.request.responseText);
            }
        }, false);
    
        this.request.open(this.method, this.url, true);
        this.request.send(this.body);
        return this;
    };

    app.js

    new HttpRequest('/users')
        .setResponseParser(JSON.parse)
        .send(function(users) {
            // Do something with users
        });
    
    new HttpRequest('/posts')
        .setResponseParser(JSON.parse)
        .send(function(posts) {
            // Do something with posts
        });
    
    // Create a new user
    new HttpRequest('/user')
        .setMethod(HttpRequest.METHOD_POST)
        .setBody({
            name: 'Tim',
            email: 'info@example.com'
        })
        .setResponseParser(JSON.parse)
        .send(function(user) {
            // Do something with new user
        });

    上面创建的HttpRequest类现在可以高度配置,因此可以应用于我们的许多API调用。 尽管实现(一系列链接方法调用)的实现更为复杂,但类的功能仍易于维护。 在实现和可重用性之间寻找平衡是困难的,并且是针对特定项目的。

    使用OOP时,设计模式会增加很多功能。 尽管它们本身并不能提高可读性,但是一致性却可以!

    人的语法

    文件,函数,对象,这些只是粗略的线条。 它们使您的代码易于扫描 使代码易于阅读是更加微妙的艺术。 最细微的细节可以带来很大的不同。 例如,将行长度限制为80个字符是一种简单的解决方案,通常由编辑人员通过垂直线来强制实施。 但是还有更多!

    命名

    适当的命名可以立即识别,从而省去了查找值或函数功能的麻烦。

    免费学习PHP!

    全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

    原价$ 11.95 您的完全免费

    功能通常是驼峰式的。 以动词开头,然后加上主语通常会有所帮助。

    function getApiUrl() { /* ... */ }
    function setRequestMethod() { /* ... */ }
    function findItemsById(n) { /* ... */ }
    function hideSearchForm() { /* ... */ }

    对于变量名,请尝试应用倒金字塔方法。 主题首先出现,属性随后出现。

    var element = document.getElementById('body'),
        elementChildren = element.children,
        elementChildrenCount = elementChildren.length;
    
    // When defining a set of colours, I prefix the variable with “color”
    var colorBackground = 0xFAFAFA,
        colorPrimary = 0x663399;
    
    // When defining a set of background properties, I use background as base
    var backgroundColor = 0xFAFAFA,
        backgroundImages = ['foo.png', 'bar.png'];
    
    // Context can make all the difference
    var headerBackgroundColor = 0xFAFAFA,
        headerTextColor = 0x663399;

    区分正则变量和特殊变量之间的区别也很重要。 例如,常量的名称通常用大写字母和下划线表示。

    var URI_ROOT = window.location.href;

    上课通常以驼峰式为例,以大写字母开头。

    function FooObject {
        // ...
    }

    一个小细节是缩写。 一些人选择用大写字母写缩写,而另一些人选择坚持使用驼峰式写法。 使用前者可能会使识别后续的缩写变得更加困难。

    紧凑性和优化

    在许多代码库中,您可能会遇到“特殊”代码以减少字符数或提高算法性能。

    单行代码是紧凑代码的示例。 不幸的是,他们经常依靠黑客或晦涩的语法。 嵌套的三元运算符是很常见的情况,如下所示。 尽管结构紧凑,但与常规的if语句相反,它也可能需要一两秒钟来了解其功能。 注意语法快捷方式。

    // Yay, someone managed to make this a one-liner!
    var state = isHidden ? 'hidden' : isAnimating ? 'animating' : '';
    
    // Yay, someone managed to make this readable!
    var state = '';
    if (isAnimating) state = 'animating';
    if (isHidden) state = 'hidden';

    微观优化是性能优化,通常影响不大。 在大多数情况下,它们的可读性不如同等性能的同类产品。

    // This may be most performant
    $el[0].checked;
    
    // But these are still fast, and are much easier to read
    // Source: http://jsperf.com/prop-vs-ischecked/5
    $el.prop('checked');
    $el.is(':checked');
    $el.attr('checked');

    JavaScript编译器确实非常擅长为我们优化代码,而且它们还在不断改进。 除非未经优化的代码与经过优化的代码之间的区别非常明显 (除非通常要经过数千或数百万次的操作),否则建议您更容易阅读。

    非代码

    讽刺的是,但保持代码可读性的更好方法是添加未执行的语法。 我们称其为非代码。

    空格

    我很确定每个开发人员都有另一个开发人员供应,或者已经检查了站点的缩小代码-删除了大多数空白的代码。 第一次碰到这个可能会很令人惊讶。 在不同的视觉艺术领域,例如设计和版式中,空白空间与填充一样重要。 您将需要在两者之间找到微妙的平衡。 对于每个公司,每个团队,每个开发人员,关于这种平衡的观点有所不同。 幸运的是,有一些公认的规则:

    • 每行一个表达式
    • 缩进块的内容,
    • 可以使用额外的中断来分隔代码部分。

    任何其他规则都应与您一起工作的人讨论。 无论您同意哪种代码样式,一致性都是关键。

    function sendPostRequest(url, data, cb) {
        // A few assignments grouped together and neatly indented
        var requestMethod = 'POST',
            requestHeaders = {
                'Content-Type': 'text/plain'
            };
    
        // XMLHttpRequest initialisation, configuration and submission
        var request = new XMLHttpRequest();
        request.addEventListener('load', cb, false);
        request.open(requestMethod, url, false);
        request.send(data);
    }

    注释

    就像空白一样,注释可以是一种很好的方式,使您的代码显得有些空虚,但也允许您向代码中添加细节。 确保添加注释以显示:

    • 非显而易见代码的解释和论证,
    • 修复程序可以解决哪些错误或怪异,并在可用时提供。

    // Sum values for the graph’s range
    var sum = values.reduce(function(previousValue, currentValue) { 
        return previousValue + currentValue;
    });

    并非所有修复程序都是显而易见的。 放置其他信息可以澄清很多:

    if ('addEventListener' in element) {
        element.addEventListener('click', myFunc);
    }
    // IE8 and lower do not support .addEventListener, 
    // so .attachEvent should be used instead
    // http://caniuse.com/#search=addEventListener
    // https://msdn.microsoft.com/en-us/library/ms536343%28VS.85%29.aspx
    else {
        element.attachEvent('click', myFunc);
    }

    内联文档

    在编写面向对象的软件时,内联文档可以像常规注释一样为您的代码提供一些喘息的空间。 它们还有助于阐明属性或方法的目的和细节。 许多IDE使用它们作为提示,并且生成的文档工具也使用它们! 无论是什么原因,编写文档都是一种很好的实践。

    /**
     * Create a HTTP request
     * @constructor
     * @param {string} url
     */
    function HttpRequest(url) {
        // ...
    }
    
    /**
     * Set an object of headers
     * @param {Object} headers
     * @return {HttpRequest}
     */
    HttpRequest.prototype.setHeaders = function(headers) {
        for (var header in headers) {
            this.headers[header] = headers[header];
        }
    
        // Return self for chaining
        return this;
    };

    回调难题

    事件和异步调用是JavaScript的强大功能,但通常会使代码难以阅读。

    异步调用通常随回调一起提供。 有时,您想按顺序运行它们,或等待它们准备就绪。

    function doRequest(url, success, error) { /* ... */ }
    
    doRequest('https://example.com/api/users', function(users) {
        doRequest('https://example.com/api/posts', function(posts) {
            // Do something with users and posts
        }, function(error) {
            // /api/posts went wrong
        });
    }, function(error) {
        // /api/users went wrong
    });

    ES2015(也称为ES6)中引入了Promise对象以解决这两个问题。 它允许您展平嵌套的异步请求。

    function doRequest(url) {
        return new Promise(function(resolve, reject) {
            // Initialise request
            // Call resolve(response) on success
            // Call reject(error) on error
        });
    }
    
    // Request users first
    doRequest('https://example.com/api/users')
    // .then() is executed when they all executed successfully
    .then(function(users) { /* ... */ })
    // .catch() is executed when any of the promises fired the reject() function
    .catch(function(error) { /* ... */ });
    
    // Run multiple promises parallel
    Promise.all([
        doRequest('https://example.com/api/users'),
        doRequest('https://example.com/api/posts')
    ])
    .then(function(responses) { /* ... */ })
    .catch(function(error) { /* ... */ });

    尽管我们引入了其他代码,但更易于正确解释。 您可以在此处阅读有关Promises的更多信息: JavaScript成为异步的(而且很棒)

    ES6 / ES2015

    如果您了解ES2015规范,则可能已经注意到本文中的所有代码示例均为旧版本( Promise对象除外)。 尽管ES6具有强大的功能,但在可读性方面还是存在一些顾虑。

    所述脂肪箭头语法定义了一个函数,它继承的值this从它的父范围。 至少,这就是设计它的原因。 使用它来定义常规函数也很诱人。

    var add = (a, b) => a + b;
    console.log(add(1, 2)); // 3

    另一个示例是rest和spread语法。

    /**
     * Sums a list of numbers
     * @param {Array} numbers
     * @return {Number}
     */
    function add(...numbers) {
        return n.reduce(function(previousValue, currentValue) {
            return previousValue + currentValue;
        }, 0);
    }
    
    add(...[1, 2, 3]);
    
    /**
     * Sums a, b and c
     * @param {Number} a
     * @param {Number} b
     * @param {Number} c
     * @return {Number}
     */
    function add(a, b, c) {
        return a + b + c;
    }
    
    add(1, 2, 3);

    我的观点是,ES2015规范引入了许多有用的但晦涩难懂的语法,有时使它们容易被单行代码滥用。 我不想阻止使用这些功能。 我想鼓励谨慎使用它们。

    结论

    在项目的每个阶段都要记住保持代码的可读性和可维护性。 从文件系统到微小的语法选择,一切都很重要。 特别是在团队中,很难一直执行所有规则。 代码审查可以提供帮助,但仍然留有人为错误的余地。 幸运的是,有工具可以帮助您!

    • JSHint –保持代码无错误JavaScript linter
    • 惯用语 -一种流行的代码样式标准,但可以随意更改
    • EditorConfig –定义跨编辑器的代码样式

    除了代码质量和样式工具之外,还有一些工具可以使任何代码更易于阅读。 尝试使用不同的语法突出显示主题,或者尝试使用微型地图来查看脚本的自顶向下概述( AtomBrackets )。

    您对编写可读和可维护的代码有何想法? 我希望在下面的评论中听到他们的声音。

    翻译自: https://www.sitepoint.com/importance-of-code-that-humans-can-read/

    编写代码的规范性可以看出

    展开全文
  • 代码评审-JAVA代码

    千次阅读 2016-10-23 20:02:52
    重要性 检查项 备注 命名         重要 命名规则是否与所采用规范保持一致? 成员变量,方法参数等需要使用首字母小写,其余单词首字母大写命名方式,禁止使用下划线(_)数字等方式命名 不要出现局部变量...
  • 代码评审是在软件开发流程中非常重要的一环,由于这个环节需要开发具有一些在写代码时涉及不到能力,如沟通能力、判断力等,所以这也可能是最具有挑战环节之一。一个功能代码可能被写成N种不同形式,这些...
  • 这篇文章是由同行评审马特·伯内特 , 西蒙·林顿和尼尔森雅克 。... 可读的代码必须保持产品维护和保持自己,和你同事或合作者高兴。 不可读代码夸张例子上可以找到JS1k比赛,其目标是到1024个...
  • 在开发之前做好设计,流程图,伪代码等前期工作是必要。可以清晰指导我该怎么做,而不是边做边想。看似浪费了前期时间,实际上节省了构建代码反复思考,反复修改时间。制定好技术方案可以交由同事进行评审,...
  • 代码评审就是源代码系统审核(也叫同业互查),目的是找到并且修复在开发最初阶段被忽视掉一些问题,以此来改进软件质量,同时提高程序员编码能力。 代码评审为什么重要呢? 引自“Code Complete” ...
  • Gerrit 为 Git 引入的代码审核是强制性的,就是说除非特别授权设置,向 Git 版本库推送(Push)必须要经过Gerrit 服务器,修订必须经过代码审核一套工作流之后,才可能经批准并纳入正式代码库中。     本文...
  • 略论研发评审的必要

    千次阅读 2016-04-19 18:58:52
    这使我意识到:每个人思维都是存在盲区,在牵涉到多个模块时的代码变动时应该有一个评审机制,确保开发者设计思路能够得到部门技术委员会审核,这样才能最大程度避免出现重大设计缺陷。 
  • 时间过真快,3月底了,更新一次博客吧,算是对三月份忙碌一个总结。 吃过饭,习惯登录qq,看到我群里一个... 不就是写个代码吗,然后写完再进行测试这个代码是否实现了这个功能。 于是乎写了一段代码...
  • 本文来自DZone,作者Matt DuVall是一名软件工程师,他在此分享可维护性在软件开发里的重要性。所谓软件的可维护性其实说简单了就是软件代码的可被修改的容易程度。为了适应新环境、满足新需求,只有对当初的设计初衷...
  • 1.代码审查对软件测试的重要性; 2.并不是所有的软件测试人员都需要阅读代码;(那哪些人需要?) 3.错误发现的越早,改正的成本越低; 4.代码检查、走查和可用性测试时三种主要的人工测试方法。代码检查和走查是...
  • 2019.4.13周六下午,在公司进行了前端小组代码评审,这是参加工作以来自己参与的第一次真正意义上的代码评审,会上,广哥主要是想通过这次的代码评审让我们知道“详设”也就是【详细设计】的重要性。 会后,我反思...
  • IOS代码重构(一)目录结构调整

    千次阅读 2017-01-20 17:07:56
    2 代码评审的重要性。在新人实习的三个月内,要对其详细讲解代码架构,使其理解,并对其提交的代码作评审,防止其另立门户,给后续代码维护买下隐患。如果有更好的建议,可以沟通之后,由系统架构师添加到项目中。 ...
  • 代码评审的 8 点建议 学校有一点没有教你的是:如何进行代码评审。你学习了算法、数据结构,以及编程语言基础,但没有人坐下来说:“这是一些能让你提出更好的反馈的办法”。 代码评审是编写良好软件过程中的关键...
  • 首先在用例评审内容上,要考虑全面,具体考虑这几点:是否覆盖测试需求上所有功能点,不违背产品原型和代码设计,用例设计结构安排是否清晰合理,有利于高效覆盖需求;是否包含充分异常测试用例;是否简洁,不...
  • 软件质量的重要性和必要性已被越来越多的软件开发人员所认识,各种质量保障工具和流程层出不穷。从根本上讲,软件是通过程序代码实现的,是代码质量的外在表现。只有提高代码质量,才能从根本上提高软件的质量。要...
  • 1、其实为什么要评审,不是怀疑测试工程师没有好好...把没有想到的测试点找出来 其次才有以下好处: 1、评审时还可以做到让开发 产品 测试 对需求达成一致理解,帮助开发提前修改代码中的bug,因为在评审的时候可...
  • 互联网平台架构日益成为互联网发展的基石,对于...本场 Chat 会带领大家从支付平台架构设计评审入手,讲解设计评审的核心要点,为读者带去现实中的案例,帮助读者理解设计评审的重要性、核心要点和最佳实现。 在这...
  • 浅谈 Code Review

    2018-11-06 13:40:15
    实际上道理大家都懂,只是真正能做到的,大概是一些大规模大一点的公司,对工程能力要求比较严格的追求,由于现在的互联网公司,产品的迭代是非常快的,如果很容易就忽视了代码评审的重要性。我们在日常的开发当中,...
  • 浅谈Code Review

    2018-11-06 13:36:00
    实际上道理大家都懂,只是真正能做到的,大概是一些大规模大一点的公司,对工程能力要求比较严格的追求,由于现在的互联网公司,产品的迭代是非常快的,如果很容易就忽视了代码评审的重要性。我们在日常的开发当中,...
  • 评审的重要性:结果显示,产品的缺陷出现最多的地方是产品需求规格说明书,而不是程序代码。 评审: 技术评审 (对产品各阶段的成果进行评估,以确保需求规格说明书,设计文档,测试计划和用例等之间保持一致,并...
  • 代码设计,是程序员做项目时,在coding之前非常重要的一个步骤,可以说关系到整个系统、整个团队研发质量和效率。一般说代码设计,可能涵盖以下几种: 1.整体设计 2.架构设计 3.领域模型设计 4.数据库设计 5.API...
  • 代码评审也称代码复查,是指通过阅读代码来检查源代码与编码标准符合以及代码质量活动。 代码优化,一个很重要的课题。它作用主要是面向代码可读性,可维护和可移植;使自己代码可靠,正确,简明,...

空空如也

空空如也

1 2 3 4 5
收藏数 92
精华内容 36
关键字:

代码评审的重要性