iOS 代码评审

2021-06-07  本文已影响0人  uniapp

1、CodeReview

1.1 为什么要进行代码评审

1.2 代码评审的方式和时间

1.3 代码评审的层级

实现正确性和设计合理性是必须要进行的 code review。对于代码可读性,由于每个人的编码风格不一样,建议做最低级别的 review,比如注释。

1.4 使用代码评审的注意点

1.5 使用代码评审的小提示

以前经历过几个相当痛苦的Code Review,那几次Code Review都是在程序完成的时候进行的,当你面对那近万行的代码,以前 N 我掺和在一起的功能,你会发现,整个 Code Review 变得非常地艰难,用不了一会儿,你就会发现大家都在拼命地打着哈欠,但还是要坚持,有时候,这样的 Review 会持续 3 个小时以上,相当的夸张。而且,会议上会出现相当多的问题和争论,因为,这就好像,人家都把整个房子盖好了,大家 Review 时这挑一点那挑一点,有时候触动地基或是承重墙体,需要大动手术,让人返工,这当然会让盖房的人一下就跳起来极力地维护自己的代码,最后还伤了团队成员的感情。

所以,千万不要等大厦都盖好了再去 Reivew,而且当有了地基,有了框架,有了房顶,有了门窗,有了装修的各个时候循序渐进地进行 Review,这样反而会更有效率,也更有帮助。

下面是一些观点,千万要铭记:

  1. 要 Review 的代码越多,那么要重构,重写的代码就会越多。而越不被程序作者接受的建议也会越多,唾沫口水战也会越多。

程序员代码写得时候越长,程序员就会在代码中加入越来越多的个人的东西。 程序员最大的问题就是 “自负”,无论什么时候,什么情况下,有太多的机会会让这种 “自负” 澎涨开来,并开始影响团队影响整个项目,以至于听不见别人的建议,从而让 Code Review 变成了口水战。
越接近软件发布的最终期限,代码也就不能改得太多。

个人的习惯,也是对团队成员的要求是:先 Review 设计实现思路,然后 Review 设计模式,接着 Review 成形的骨干代码,最后 Review 完成的代码,如果程序复杂的话,需要拆成几个单元或模块分别 Review。当然,最佳的实践是,每次 Review 的代码应该在 1000 行以内,时间不能超过一部电影的时间 1.5 小时。

当然,在敏捷开发中,他们不需要 Code Reivew,其实,敏捷开发中使用更为极端的 “结对编程”(Pair-Programming)的方法:一种时时刻刻都在进行 Code Review 的方法,个人感觉在实际过程中,这种方法有点过了。另外,大家可以看看《结对编程的利与弊》来了解一下这种方法的问题。

  1. Code Review 不要太正式,而且要短
  1. 只有在 Checklist 上存在的东西会被 Review。
  2. Code Reviews 变成了一种礼节性的东西,你的同事会装做很关心你的代码,但其实他心里想着尽快地离开你。

只有不正式的 Code Review 才会让你和评审者放轻松,人只有放松了,才会表现得很真实,很真诚。记住 Review 只不过是一种形式,而只有通过相互的讨论得到了有意义和有建设性的建议和意见,那才是最实在的。不然,作者和评审者的关系就会变成小偷和警察的关系。

  1. 尽可能的让不同的人 Reivew 你的代码
  1. 从不同的方向评审代码总是好的。
  2. 会有更多的人帮你在日后维护你的代码。
    3.这也是一个增加团队凝聚力的方法。
  1. 保持积极的正面的态度
  1. 学会享受 Code Reivew

2、实用的 Code Review 工具

2.1 Review board

2.2 Codestriker

2.3 Groogle

2.4 Rietveld

2.5 JCR

2.6 Jupiter

3、改善代码质量的一些方法

3.1 减少对象属性

局部变量不需要多说,需要写码的时候思路清晰一些,写完之后在 commit 之前即使 review 一定要 check 一遍,对自己的代码质量负责,code review 往往检查不出来冗余或者废弃的代码。不添加一个多余的对象属性,不留注释掉的代码,不留没有用途的代码,这些都是基本功,但是很多开发者就是做不到,或者说对写码没有爱,所以很多废弃的代码,我重构代码的时候,虽然对业务不熟悉,但是大多数模块都能删除掉十分之一的代码和大量的对象属性,这个是单纯的不够用心。

3.2 减少和模块化对象消息

减少 UI 的 action 类消息,感谢 block 和 RAC,或者 blockskit,让我们得以通过 hook 来把之前 target-action 模型换为 block 来实现,UI 和 action 的代码终于可以一起了,使整个逻辑变得紧凑,在查看代码的时候终于不用跳来跳去了。还有就是日常开发中,把自己写的各种 protocol 或者传递 target/selector 的地方,尽量使用 block 来代替,相信我,这个会使代码好读很多。

使用 “#pragma mark - XXX” 进行分割不同逻辑之间的界限,让整个文件阅读起来更加结构化。还有一个我现在最常用的就是是设置 Xcode 的快捷键,把 Ctrl + 6 显示文档结构的快捷键改为:Command + D ,搜索来快速跳转到对应的消息和模块,要尽量避免文档结构显示超过两屏幕,超过两屏幕说明有点多了,你肯定考虑一下重构了。

个人习惯一般划分的模块有:life cycle,ui helper,datasource/delegate,依据功能进行划分的模块等等。

3.3 MVVM && RAC

3.4 UI 开发

重写 UI 的 getter 方法,把 UI 的初始化放在 getter 中,减轻 -viewDidLoad 的负荷,同时可以使整个页面变得清晰;同时,可以通过使用使用 GCC Code Block Evaluation C Extension ({…}) 语法,结构化局部变量初始化和处理的逻辑。

举一个例子,-viewDidLoad 中,做为逻辑的入口,代码会变少但是变清晰,代码如下:
然后重写 bgView 的 getter 方法,包括 View 和 frame 这些都可以使用 ({...}) 语法使代码结构化层次化:

*复杂 UI 的开发

有时候我们开发业务的时候,产品需求往往非常复杂,酷炫的 UI 加上各种考虑全面的逻辑,这个的结果就是,码农的超长代码,而我们平时工作面对的也大多数都是这类问题。关于这个问题,解决方式是组合式 UI / custom view / child view controller 来解决。

1 组合式 view
这个概念是从 Android 中借鉴而来。重构时查看项目中的代码,发现大家用的做 UI 的时候,对这个概念不是很强烈,感觉是对 UIView 的 view hierarchy 理解不够。比如一个复杂的 UI,直接把所有的 subviews 直接堆积到 super view 上面,这样的结果就是,调整 subview 的 frame 非常困难。我个人的做法是,首先对复杂 UI 进行分块,从左到右或者从上倒下,把各个 UI 元素放到不同的 container view 上面,然后组合这些 container view 放到 super view 上面,这样的好处非常明显,首先 UI 干净清晰,阅读起来不那么费劲。其次就是你计算坐标或者设置约束会变得很简单,因为你调整一个 UI 元素的时候,只需要考虑它与包含它的 container view 的坐标关系即可,而不是通过一大堆无趣计算跟最外层 super view 关联起来。还有就是可以充分利用 Auto Layout 和 autoresiziingmask 这些 UI 利器,使用的时候会非常方便。再有就是结合 RACObserver 这个利器之后,你能很容易做到根据 data 来 update ui。

举个例子,是我们项目中前一段时间我重构的一个页面,这个首页列表,性能要求比较高。并没有使用 Auto Layout 来实现,但是不使用 Auto Layout 并不是不把它写的很干净的理由。
这是我对一个 UITableViewCell 的分层,最外层由 icon view / right view / bottom view 这些 container view 组成,而 right view 这个 container view 则又是由 right top view / right middle view /right bottom view 这些 sub container view 组合而成,而具体的 UI 元素则是放在这些 sub container view 之中。这样 UI 代码就会以一种层次化样式展示出来,init/layoutsubviews 只需要维护 self 与container view 的关系即可,而具体展示数据的 UI 元素也只跟 sub container view 存在坐标关系。我们看一下 right view 这个 container view 的代码实现: 5 6 7 * 关于性能的话,感谢 iOS,我们不存在 Android 中页面层次较深性能卡顿的问题,放心把 UI 层次化就行。

  1. custom view
    对于非常复杂并且相对独立或者可以重用的 UI,及时使用 custom view 子类化。对于单纯的展示 UI,我们只需要简单通过组合式 view 就可以实现了。但是有时候,我们会遇到一些包含无论是动画,逻辑都比较复杂的情况,这个时候使用组合式 View 去实现,一方面容易把逻辑弄混乱,会把文件的文档结构变得很复杂,简单来说就是对象的消息数量很多。这个时候,我们可以通过 custom view 来实现,实际上这个也是组合式 view,但是我们是把这些组合式 view 变成了一个类而已,只暴露少量的接口给外部调用。如果这个 custom view 会出现在多个业务模块中,那么有必要使用一个单独的文件来容纳这个类,如果仅仅是这个模块一个使用的话,可以直接写在这个业务模块的文件中即可,没有必要对所有的类都单独一个文件,我们就当作这个 “内部类” 来弄了。

什么时候使用 custom view 而不是组合 view,我想了很久,你觉得组合式 view 的代码很乱的时候,别客气,包装为一个 custom view 就行了。我这边最近遇到的几个问题是使用 UICollectionView 来做部分 UI 的时候,同时还有其他很多 UI 元素,我会写一个 custom view。比如把一个左右滑动查看图片的 UI 使用 PhotoView 这个 custom view 进行包装,内部使用 UICollectionView 实现一部分相对独立的模块,这个时候这个控件实际上是可以包装为一个相对独立的模块的,用子类我感觉比较合适一些。

  1. container view controller
    这个用法很多开发者不熟悉或者说是用的不多,但实际业务中,这个技术非常有用途,可以大大提高开发效率。对于有相对独立业务逻辑以及生命周期要求的业务,使用 child view controller 进行包装,如果 parent view contrller 与 child view controller 之间非常密切,则使用 View Model 以及 block 来对 parent view controller 和 child view controller 进行衔接。

使用 child view controller 来开发 UI 而不是 custom view 的优势很多,我个人认为最大优势在于可以方便利用 View Controller 的生命周期以及 View Controller Hierarchy,比如在 -viewWillAppear/-viewDidDisappear 中做一些操作,再比如直接获取 UINavigationController 指针等等。之前的做法一般是在 View Controller 的对应生命周期内调用 custom view 的方法,传递 self.navigationController 指针给 custom view 等。所以可以不仅仅把 UI 相关的代码包装进入这个 child view controller,也可以把网络请求,数据处理这些这些逻辑放到 child view controller 中,这样下来就能避免那种动不动超过 1k 行的 view controller 的出现了。

利用 MVVM 之后,还有一个比较有好处的用法,比如公用一些数据的时候,之前我们是把对象传递来传递去,这样的问题是很容易出现混乱,这个时候我们是传递 ViewModel 就可以避免这个问题,ViewModel 既负责网络请求又负责数据处理,而 parent view controller 与 child view controller 所需要做的事情就是跟 ViewModel 进行 binding 而已。

3.5 Auto Layout/Masonry

说一下 Auto Layout 的问题:

使用 Auto Layout 有一个比较大的问题在于动画,通过更改约束来进行动画,一直是我比较头疼的问题,所以一般遇到这类问题的时候,我都会尽量避免使用 Auto Layout 来解决,而是使用 frame 的方式来做。可以参考 objc.io 上面的一篇文章。

iOS7 以及以下的操作系统上,UILabel 显示多行文本是有不足的,你需要设置 UILabel 的 preferredMaxLayoutWidth 为一个固定值才能显示多行文本。在 iOS8 以后就不再需要设置这个了。

这个地方,我的建议是根据具体问题来选择实现方式:spring & structs 也好,Auto Layout 也好,那种解决问题较为简洁快速就用那种,不一定非要固定于一种行为,尤其是开发的页面有大量动画的时候。

3.6 注释

3.7 善用 OC 的新语法

3.8 JSON 数据的处理

3.9 block

3.10 提交代码

3.11 RAC 封装网络请求

原地址: https://www.daimajiaoliu.com/daima/3eae2a2909003fe

上一篇 下一篇

猜你喜欢

热点阅读