iOS实践:一次失败的重构记实

iOS实践:一次失败的重构记实

摘要:

2月15日,原代码分析,研究重构点

严重问题:

多类型列表的数据源控制,不仅使用了多个数组,还使用了一个包含所有数组的大字典来做统一管理。导致以下问题

有意思的是,我本以为UI部分也会这样。但事实上,比我想象的要好非常多。有类型区分,有管理。UI的主要问题是没用自动布局,及其严重的增加了成本。尤其是对于动态的内容高度等计算。

解决思路参考:

分析自适应解决方案

打算引入SDAutoLayout这个三方自适应。初步研究后,发觉能较好的适应tableView的自适应高度和Label的自适应高度。而且这个项目现在有专门人员在github是维护,且项目更新频率很高。

2月16日,尝试进行自适应和图片加载重构

数据方面的重新梳理和关系重构。

原来的数据model类中居然包含单元格高度属性…也是够了

这是一个典型的view和model未分离的情况。

重新命名,并修改内部相关属性。

这个世界上,总有一些傻逼是你躲不过去的。

现在是下午两点,简单说一些上午到现在做的一些东西。

确认使用框架后,先对详情页的主贴和续帖进行重构。接下来进行了几项尝试。

  1. 在原CellView上进行修改。相继出现多过崩溃异常。放弃

  2. 重新撰写简单的CellView(只包含title 和一个 imageview)。进行调试,文本的自动适应和图片的自动适应相继成功。

  3. 重新尝试1,但先进行cellview中,更改为autolayout,再进行自适应。

相继出现各种不出现,同时由于方法相互关联太多,越更改越困难,调试也更加困难。

  1. 重新尝试2,即从刚才较为简单的模型上添加控件,丰富界面,然后迁移点击事件。

好吧。还是失败了。工作量太大,而且迁移的过程中存在大量的自定义view,导致需要查看大量自定义view,显得不是很现实。再想别的办法。

2月17日,重构进行中

帖子详情页里,主贴,细小的功能非常之多。比我想象中的要困难很多。文本,文字很多需要转富文本,而且同时,还支持各种各样的点击。

主要的图片问题,终于不得不面对了。帖子详情页的图片加载异常混乱,每次加载完一个图片,就会调用界面重绘,极大的加重了UI负担和界面不可控。也是引起帖子详情页加载会崩溃的原因。

所以,暂时决定暂停UI,先行处理图片加载问题。

比我想象的还要困难。略有小感:

重构中困难的是取舍,原先代码是很糟(不糟谁重构啊),但却不能一下子全部抛弃,如果全部推翻重写的成本过于昂贵。
所以,预想中逐步重构,一点一点推翻。
但问题又来了,原先耦合性高且冗杂,加上复杂的业务逻辑,导致改一点就会引起新的问题,又要填补新的解决方案,反而被重构拖累,逐步更改的成本就会越来越高。
这是一个度的问题,但问题是,谁TM告诉我,这个度在哪里!!!

打算使用较为优秀的SDWebImage框架。Demo测试通过,开始集成到项目中。

集成过程异常艰辛。

  1. 通过pod包管理集成,出现异常。有重复类版本相撞无法通过编译。
  2. 艰难查实的确存在,但置于一个叫MW…的文件中的lib文件夹下。
  3. 简单查阅叫MW…这个鬼的用处,根本找不到用在哪,心好累,又不能直接暴力删除。也是够了!
  4. 直接替换源码试试。 试验失败了,直接替换掉源码,导致另一些类报错,数目很多。估计是对源码进行了加工修改。只能放弃。

妥协方案,用较旧的三方暂时实现图片加载。

失败:

重新回到自适应上,虽然有了一套对于自适应使用的流程代码,但对于复杂又多类型又过于动态的列表仍旧不能适应。需要补充的判断实在是过于复杂,所以,这期自适应,预计将搁浅。

先在较为简单的列表里试验,然后再着手处理复杂还多图的列表吧。

2月18日,UI改造。

改了快一天UI,感悟重申:想要一层层重构,最大的难点其实是对原代码的解读上。最大的成本也是。因为糟糕的代码配合特别动态的逻辑,衍生出来的复杂程度可见一斑。

今天遇到的巨大的问题,更改一处UI,会衍生新的UI问题,更改新的UI问题,又可能会衍生出新的问题。遇到了重构需要换多少血才行,当然是全换最好,可时间和人力成本却不可负担。如果只是更换部分,就会引发多米骨牌,连续的问题会让重构变成焦油坑。

iOS的视图,容器对控件或者父类视图对子类控制能力太弱。列表视图居然需要手动计算每个具体单元高度,这让我非常难以接受,如果计算出错,可能会导致上一个单元的内容遮盖下面单元格的内容,这点让我更加难以接受。同时也让我在进行抽离时,如履薄冰,不知道动哪里会影响到相关方法。

大概遇到两个不得不思考解决的适应问题。

  1. 图片载入对UI刷新的影响。
  2. 文字控件对文字是否能自适应高度。(文本控件居然没有一个属性,自适应高度。这不是刚需吗?程序设计应该要有的啊?想不明白!!!)

UILabel的适应解决方案:

//初始化添加属性
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;

// 填入文字后添加
label.text = data.content
[label sizeToFit]

//注意:只有有宽度的label才能自动分行适应。

2月19日,继续改造(图片逻辑处理方案以及一些感想)

对图片进行改造。

粗定一个图片改造计划。

图片服务交给第三方,真的要交给第三方!现在三方对于图片的服务和管理真的已经很优秀了。我们是基于又拍云的服务提供。

——血泪教训

  1. 不改动原先代码核心逻辑。一是平稳,而是原先代码的编写过于复杂,阅读成本就非常高,更改成本就更不可控了。

原先的工具类,图片加载的方法需要传递八个参数。八个参数!八个参数!八个参数!真是疯了。这里犯了一个较为明显的错误,参数太多!

方法参数是趋向于越少越好。参数目的是为了控制方法的实现能力,参数越多,实现的能力越强,但实现的情况和结果也越多,而且,每增加一个参数,对于实现出来的结果可能性都是成倍的增加,对修改成本也是很大,无从下手,也无法修改,巨大的不确定性,让这个方法理解和使用都有巨大的成本,对于随后维护的工程师更是大大大大的成本。

所以,方法的参数,没有自然是最优。一个参数,很漂亮,也很自然,基本也不用具体看方法实现。两个参数,已经开始多重方向的控制了,有时需要进入方法具体实现查看。三个参数,必须进入方法具体实现来查看,而且,找三个参数扔进这个方法已经是高额成本了。四个参数,对不起,你写的这个方法有问题。

当然,参数越积越多总是有原因的。一个很大的原因是,参数间本身是有关系,或者是协同一起去控制方法走向的,这时候,应该将几个协同合作的参数封装成一个类,以类的形式对外暴露。这是最直接也是最有效的重构。

  1. 只更改从又拍云上获得图片逻辑,并与原代码逻辑脱离,单独新建方法,并封装新类进行新的图片逻辑撰写。当然,新方法不支持从老式图片服务器拉图片。

对旧系统的维护和支持要逐步进行替换和更迭。这两年花费了大量时间用户进行旧版本的适配支持,但淘汰率在时间上却很快。成本沉没率很高。现在想想也对,需要对旧版本进行适配和技术提供,就需要更多的时间去设计和修改问题,但这段时间里,新旧迭代的时间却也很快。大概最明显的例子,就是对于iOS 6789的支持了。

  1. 随后的新功能,新代码将缓存和加载这件事情上交给三方。

随后会再写一篇文字,关于我们到底用不用开源,用多少好。都说适度的使用较好,尼玛!到底什么叫适度,我会写一篇自己的理解出来。

原本的代码是通过类扩展的方式实现的,所以直接在类扩展里加入了新的类扩展方式去实现。然后调用代码也简化了。基本功能已经跑通。

2月20日,图片加载模块重构

昨天已经跑通的基本功能,今天主要是对于图片加载重构的设计和规范。

用了比较直接暴力的方法,直接引用使用,所有的缓存复用等交给依赖包。

具体参考图片加载设计和规范

然后,便进入了重构过程中最最无聊的体力活阶段了。

comments powered by Disqus