1
saharabear 2013-06-07 21:00:42 +08:00 1
乱就乱吧,真实。
|
2
wog OP @saharabear
那就太好了,我还在考虑是不是应该清空github的记录呢 |
3
alexrezit 2013-06-07 22:41:16 +08:00
@wog
想清就清吧. 反正我自己的 Github 上比较老一点的 repo 都删了, 留着丢人且无用, 更糟糕的是还容易误导别人学习一些不好的编码习惯. 不知道你是说一个文件两千多行么? |
4
wog OP @alexrezit 不是,整个一个项目超过两千多行就感觉控制不了了,是特别是c++的,继承什么的一多就乱了,反倒是c的还好点,不会太乱
|
5
fangzhzh 2013-06-07 23:47:22 +08:00 7
我是OO software engineer, 所以例子难免使用很多oo的概念.
设计模式,面向对象, 都是一种手段,不是目的. # 几个大原则: * 先想框架, 再想细节. * 代码要分层, 划分好边界. * 把最容易变化的部分抽象并隔离出来. * 一个比较虚的, 简单->复杂. 考虑的足够复杂, 实现就可能很简单. * 解耦合. 分配好职责,一个类只做并做好一件事情, 通知机制尽量不要使用依赖过强的方式. ## 先框架, 再细节 上来就写代码不是一种好习惯. 写代码前, 技术选型以后, 先不要想代码上怎么实现. 要不要多线程, 是不是要使用stl, boost, 是不要要使用一些第三方库, 是不是要自己实现链表, 字典等等. 这个功能是不是适合一个排序.先不要从这些地方想. 先想一想, 要做什么,逻辑上可以分成几个部分, 每个部分的关系, 之间的联系. 然后再想每个部分是什么, 需要具体做哪些工作, 实现哪些功能. 最后再考虑这些功能需要使用什么技术. ## 分层 ### 大方面: 一般是MVC, M数据层, V层肯定是要分开的. 控制层简单了和UI混在一起,有时候单拎. ### 小方面: 一般的小功能一个工作类就可以搞定了. 稍微大一些的,举个异步的列子. 实现上一般有一个 manager管理所有的请求, 或并行, 或队列串行, 把请求分发给正确的工作类. 工作类结束了, 把结果交给manager , manager负责把结构返回给请求者. 层次上, 工作类和管理类分开, 客户只看到了管理类的统一接口, 接口类不变, 工作类可以有无限增加, 并且可以透明替换. 那么client不再依赖工作类, 边界划分的很清楚. 一个项目改动最多的就是工作类--即业务逻辑处理类. 分好层+边界, 多次的修改也不会对框架, 层次破坏, 也就不会乱了. ## 把最容易变化的部分抽象并隔离出来 四人帮的设计模式你如果看过的话, 应该看到过这句话很多次. 把最容易变化的部分抽象出來, 就可以打到添加,修改需求时, 改动不影响以前代码最小. 抽象不是为了重用, 而是为了被重用. 接口是抽象的一种实现方式. 如果设计的足够精良, 那么你的设计就会对修改封闭, 对添加开放. 举个烂大街例子: 你设计个一个类叫animal, 你需要实现叫声这个方法, 你可以使用 if( 汪星人) 汪汪 else if( 喵星人 ) 喵喵 …. 于是每增加一个动物,你的代码就要加上一行 else if, 修改原来代码. 如果把此接口抽象出来, 每个动物尽管实现自己的doBark好了, 那么 代码简单到 ani.doBark(); 具体doBark, 由自己确定, 以后增加了类, 只需要这个类实现了doBark接口, 就可以不修改以前代码的基础上, 直接被以前的代码使用. 这个例子太简单, 太肤浅, 其实根本说明不了什么. 但是这种想法是要牢记的, 把*最容易变化*的部分抽象出来. ## 一个比较虚的, 简单->复杂. 考虑的足够复杂, 实现就可能很简单. 这个本来就很虚, 说起来就更虚的. 最好不说了. ## 解耦合. 通知机制尽量不要使用依赖过强的方式. 我说一个实际的问题吧. c++的数据库类D. 负责接受请求, 查询数据库, 将数据发送回去. 最显然的解决方案是: 客户类A像数据库类D发送请求, D分析请求, 是全部查询, 还是部分查询, 是不是可以查询, 还要考虑多个A之间的互斥. 如果可以查询, 那么D查询数据库, 打包取回来的数据, 返回给A. 如果不能查询, 那么本次的请求就丢掉了. 一种解耦合的方式, 队列+变量. A的请求, 请求时更新 最近一次的请求时间, 把具体请求入队列, 然后A就可以返回. D 根据自己的状态, 看是否有足够资源执行此次请求, 不行,就队列中等待. 直到有足够资源执行此次请求. 打包结果, 放入结果队列. A可抵达, 使用回调函数, 通知A 返回的结果. 如果A此时不可用, 同样后台等待下次发送结果. 这样保证了,请求不会丢, 结果不会丢, A不用无限等待D的执行过程. 解耦了A的请求与数据库查询操作. # 上边是战略,下边讲一下战术 * 改代码尽量不影响以前的逻辑 * 复杂的程序逻辑,先用一些条件去掉不可能的情况 * 编写完代码的选择 ## 改代码尽量不影响以前的逻辑 这个很容易理解,不容易做到. 这个在修改已有的代码的是很重要的. 千万不要*随便修改*已有的经过检验的业务逻辑, 哪怕你一百万的确定,你可以改对. 不要那么做. 需要需要修改以前代码的情况,大多数是新增了需求, 那么找到合适的位置, 把以前没有过滤的情况,过滤掉. 不要直接修改以前的代码. ## 复杂的程序逻辑,先用一些条件去掉不可能的情况, 每一个顺序下去的条件,都是互斥的 我以前写代码习惯这样 if(可行) { if( 条件1) bla; else if(条件2.1 && 条件2.2 ) { if(条件4) } } 这种代码写下去,很恐怖. 后来学会了, if(不可行) return; if(条件1) bla; if(!条件1 && (条件2.1 && 条件2 )) // !条件1, 这个保证了和上边的互斥, 在特别复杂的逻辑时,要容易理解的多 bla; ## 编写完代码的选择 一般人编完代码,就Run and Pray. 但是这是事倍功半的. 一种实践证明的方法是自己code review. 自己的代码刚写完是很难发现错误的, 所以我有一些 checklist * 数据切片 关键数据, 用搜索功能, 遍历他出现的地方, 是不是出现了不该出现的地方, 是不是在该出现的地方没有出现,这种办法可以杜绝很多的低级的 typo错误. 而这种错误是最难找的. * 控制切片 遍历所有的if else, 是不是覆盖了你想要的所有情况, 多否定自己的想法, 如果还有其他情况呢, 如果不是专业昂呢. 脑海中做几个边界测试, for, while的上下边界, if的典型数据. 太多了, 码字辛苦. 虽然码字有这么多,我认为对楼主的帮助仍然不会很大. 可能会让楼主觉得, 哇哦,好牛逼啊. 但是实际操作上, 楼主仍然觉得是没有操作性. 所以,我真正的建议, 找一个好的leader,或者伙伴,表现你的诚意,和可以栽培的潜力, 一个好leader ,可以让你的成长速度加倍, 有些东西是实践中来的,必须是你做了烂的设计, 别人做出不一样的设计; 或者你写了烂代码, 别人给出不一样的代码, 让你对比,你才会有切身的体会, 深刻的体会. 纸上得来终觉浅,绝知此事要躬行. |
7
fangzhzh 2013-06-07 23:56:26 +08:00 1
哦, 代码不支持排版, 我放到博客上了, 勉强可以看一看 http://fangzhzh.info/post/%E8%BF%91%E6%9C%9F%E9%A1%B9%E7%9B%AE%E7%9A%84%E4%B8%80%E4%BA%9B%E5%BF%83%E5%BE%97#content
|
9
soli 2013-06-08 09:54:22 +08:00 1
继承是罪魁祸首
尽量不用继承;不得不用的时候不要超过2层;不得不超过2层的时候坚决不超过3层。 |
10
xupefei 2013-06-08 10:05:20 +08:00 1
研读一下设计模式,之后就不乱了。
|
11
dreampuf 2013-06-08 10:53:33 +08:00 1
可操作层面:
原则(KISSY,SOLID)为主,模式为辅 制定约定(代码规范,项目规范,团队规范) 方法论: 一致优先,简洁其次,优美最尾 |
15
zhangdawei 2013-06-08 11:16:55 +08:00
解耦,功能性函数不超过200行,最多最多,
|
17
wog OP @zhangdawei 那功能性函数多了还很乱怎么办,还要想着怎么样复用,还要接口怎么设计,感觉管理起来有点力不从心
|
18
zhujinliang 2013-06-08 11:56:37 +08:00
慢慢来,写得多了就能驾驭了。项目不急的话把编程当作艺术。
|
19
Golevka 2013-06-08 12:24:33 +08:00
一直以来都感觉ED们不明觉厉. 为了不修改已有代码搞出一套dispatch真的很重要么? 至少我用Standard ML从来都是直接case animal of [blah blah blah]的.
|
20
railgun 2013-06-08 13:19:44 +08:00
把你的git地址发上来,我们看看有多乱233
|
21
zhangdawei 2013-06-08 14:15:15 +08:00
@wog 我的做法是这样的,仅供参考,
1,之前说过的,尽量一个功能性函数解决一个单一的问题,不要试图在一个函数里解决很多问题。 2,针对一个功能模块(自己划分),管理一个文件,用来定义和声明所需要的函数。 3,对于函数尽量减少复用,复用意味着在一个函数里增加判断和代码,增加耦合。 4,模块与模块之间定义统一的接口,不穿插定义。 5,不怕文件多,就怕文件大, |
22
cyberscorpio 2013-06-08 14:48:19 +08:00
没有银蛋,设计模式更不是什么万能的灵药,而且很容易被滥用。
在设计模式滥用的情况下,它带来的问题只怕比解决的更多。 要想代码不乱,攻守俱有法度,无他,唯手熟耳。 |