要你命三千:老代码中的那些坑

本文分享了一个开发者在维护老项目时遇到的各种代码陷阱和混乱规范,从变量命名、界面布局、委托使用、第三方库引入到类职责分配等多个角度揭示了代码中可能存在的问题,以及维护过程中的挑战与困惑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在给以前的老项目维护,说起来工作很简单,一个字:改Bug。这看起来平淡无常的工作,实际上凶险无比,藏坑无数。时至今日,感觉整个人都得到了升华。在睡觉前抽空写篇博客,和各位分享一下踩坑经历,一起品味其中的种种酸苦辣 (没甜)。

为保证个码隐私,文中代码均为化名,还望谅解。如有雷同,纯属巧合 (可以通过 git blame 查看是谁写的)。

第一回:变量命名没点数,有时写着还手误

如果要折磨一个强迫症,最好的方法就是用各种恶心的变量名恶心死他。

什么?你说首字母要大写?

1
@property (nonatomic, assign) PERSONTYPE personType;

什么?你说单词里面要小写?

1
2
3
4
typedef enum tagPersonType{
    person_type = 1,
    group_type,
} PERSONTYPE;

什么?你说要用英文单词命名?

1
- (void)uploadSeccess:(MessageEntity *)message;

什么?你说类前面要加前缀避免冲突?

1
2
3
4
5
@interface PMWLogger : NSObject
...
@interface PMTool : NSObject
...
@interface MainControler : NSObject

什么?你说文件要按照目录存放?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- Classes
    - MainControllers
        - MyController
        - Controllers
        - SettingControllers
        - ChatModel.h
        - ChatModel.m
        - SettingControllers (不是手误)
    - Chatting
    - SearchView.h
    - SearchView.m
    - Voice
    - AgentModels
- Public 
    - Common
    - PublicDef.h
    - PublicDef.m

什么?听说OC可以用宏定义?

1
#define STRHASSBUSTR(str,subStr) ...

各位看官,这,能忍?

正所谓:

命名拼写看心情,文件目录不分明。
随机掺杂宏定义,鸡不安也犬不宁。

第二回:界面全靠神奇数,保准看到就发怵

前阵子在做 iPhone4 和 iPhone6 以及 iPhone6 Plus 的适配工作。

由于历史原因没有用 AutoLayout ,也由于历史原因老代码的布局全是用数字一个一个写死的。这就给适配带来了莫大的困难。

随便拣点代码给大家欣赏欣赏:

1
UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 241, 320, 28)];

0 这种数字还好说,241 就完全让人摸不着头脑,至于 320 这个改成屏幕宽度倒也就还好,但是 28 这种神奇数字又是什么呢?

这种代码就是冲着干死队友的不偿命的态度去的。虽然写起来容易,但是维护困难,可读性极差,尤其是有多个控件布局的时候,依赖关系不明显,如果调整布局需要挨个重新计算并设置值,维护起来的酸爽,谁用谁知道。

要说神奇数字,集大成者莫过于此:

1
CGRect rect = CGRectMake(12.2+(page-1)*320+42.5*(i%7),((totalRows-1)%3)*55+2,42.5,42.5);

那天早上看到这代码差点就抱着键盘委屈的哭了出来。

正所谓:

界面写法各不同,歪门邪道千万种。
有朝一日被辞了,你的代码我不懂。

第三回:私有公有混一处,代理委托亦糊涂

在聊天的时候有这样一个数据类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@interface HBTalkData : NSObject
{
    UIImage *_firstImage;
    NSArray *_imageArry;
    id _contents;
}
@property (nonatomic, assign) NSInteger messageId;
@property (nonatomic, strong) id contents;
@property (nonatomic, assign) NSTimeInterval timeInterval;
@property (nonatomic) BOOL fromSelf;
@property (nonatomic) BOOL isGroup;
@property (nonatomic, assign) HBTalkDataStatus talkDataStatus;
@property (nonatomic) HBTalkDataContentType contentType;
@property (nonatomic, strong) PersonInfo *personInfo;
@property (nonatomic, strong) UserInfo *cardUser;
@property (nonatomic, assign) CallType callType;
@property (nonatomic, strong) NSString *duartion;
@property (nonatomic, strong) NSString *mPhoneNumber;
@property (nonatomic, strong) NSString *imageList;
@property (nonatomic, strong) NSString *msgDesc;
@property (nonatomic, readonly) UIImage *firstImage;
@property (nonatomic, readonly) NSArray *imageArry;
@property (nonatomic, assign) float     cellHeight;
@property (nonatomic, assign) CGSize    textSize;
@property (nonatomic) NSTimeInterval voiceDuration;
@property (nonatomic) CGFloat dataSize;
@property (nonatomic) NSUInteger bubbleCount;
@property (nonatomic, copy) NSString *chatUserName;
@property (nonatomic, strong) MessageEntity *originalMessage;
@property (nonatomic, strong) HBTalkDataRegisterInfo *registerInfo;
 
-(void)reset;
- (NSString *)bubbleDescription;
...
@end

纤弱的头文件里塞满了各种属性定义和方法定义,仿佛可以听到头文件的不满和娇喘。

给大家出个题:看下下面的内容,猜一下这个类的文件名是什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
... // 此处省略20行
 
@interface PersonInfo : NSObject
... // 此处省略20行
@property (nonatomic, assign)BOOL     isGrey;
@property (nonatomic, assign)BOOL     isBlack;
@property (nonatomic, assign)BOOL     isTop;
@property (nonatomic, assign)BOOL     isStar;
 
- (BOOL)isStranger;
- (BOOL)isIndividual;
- (BOOL)isDuDuSecretary;
 
@end
 
@interface UserInfo : PersonInfo
... // 此处再省20行
@property (nonatomic, assign)BOOL     mobileVerified;
@property (nonatomic, strong)NSString *countryCode;
@property (nonatomic, readonly)NSString *dialogName;
@end
 
@interface GroupInfo : PersonInfo
... // 此处又省20行
@property (nonatomic, strong)NSString *creater;
@property (nonatomic, assign)int      memberCount;
@property (nonatomic, strong)NSString *members;
@end

嗯然后这个文件叫做 UserInfo.h ,头文件将近100行。大兄弟,我读书少,你不要骗我。把三个类塞在一个文件里这种行为,除了难为队友,实在是没看出来有什么其他动机可言。

正所谓:

头文件里地方小,塞到一处并不好。
外部对象都知道,安全问题可不小。

第四回:消息通知满天飞,委托方法一大堆

我一直在想,到底是什么,让这个项目的开发人员对 NSNotificationCenter 如此痴迷,痴迷的令人陶醉。

在通过 Model 调用业务逻辑的时候,它这样发了一条命令:

1
2
// 喂,LOGIN_MODEL,帮我查下有没有更新
[LOGIN_MODEL versionCheckFromAbout:YES];

这个业务是用 GCD 开了新线程来做的,在后台检查有没有更新,如果有更新那么版本号后面会加个感叹号。那么问题来了:你咋告诉我你检查的结果是有更新还是没更新呐?难道要写 个委托?然后定义个方法?然后更新的时候指认委托?然后有了结果再告诉委托?听起来就很烦躁嘛那干脆就用通知好了:

1
2
3
if (self.versionStatus != VersionStatusNormal) {
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFY_HAS_NEW_VERSION object:nil];
}

然后在需要做处理的类里面添加 Observer 就可以了:

1
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myIconShouldChange) name:NOTIFY_HAS_NEW_VERSION object:nil];

哈哈哈哈搞定了。

哈哈哈哈你个头啊!整个项目里类似于这种的通知就有十来个,这还是有宏定义的,好追杀一点。对于那些没有宏定义的,随手一写复制粘贴的,不知道还要填坑多少。

通知虽好,但也不要贪杯啊。

看起来轻松,只是 post 了一下就搞定了,但是在 Debug 的时候有点麻烦。尤其是如果有多个 Observer ,改动的时候牵一发而动全身。如果真的是有这样使用的必要倒也罢了,但是本来一个 block 或者 delegate 就能简单清晰的解决,现在却被搞得这么繁重,实在是没有必要。

而且 NSNotificationCenter 的代码基本是一种变相的复制粘贴,十分的不工整。这是个人恩怨了,撇开不提。

NSNotificationCenter 这种只是不痛不痒的小问题,仅仅是逻辑不够优雅,关系不够清晰罢了。但是如果委托使用不当那是恶心的不行。看下这个聊天页面:

1
@interface ChattingViewController () < UITableViewDataSource, UITableViewDelegate, UITextViewDelegate, ChattingActionsPanelDelegate, ChatModelDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, HBTalkTableViewCellDelegate, EGORefreshTableHeaderDelegate, XTImagePickerControllerDelegate, ChattingInputPanelDelegate, VoiceRecordingButtonTrashBinViewContainer, ChattingUserDetailPanelDelegate, VoiceRecordingButtonDelegate>

这是一个 真实的故事 。整个类将近3000行,有2000多行是委托里定义的方法,你能信?

在这三千行代码里漫步,万事都要小心。因为你不知道 callIn 这种方法到底是定义的私有方法,还是在委托里定义的方法。#pragma mark 自然也是看心情加的,说不定加错了你也不要当真。

有时候委托都删了不见影子了,但是委托里的各种方法还留在以前的类里。

没人敢动。

How to play.

正所谓:

异步回调用通知,委托多的令人痴。
反正老子看不懂,不写代码光写诗。

第五回:第三方库无出处,随手改动无备注

相信做 iOS 的都知道 AFNetworking 这个网络库,在我们的项目里 AFNetworking 分两种,一个是别人家的 AFNetworking ,一个是咱们的 AFNetworking。对奏是这么任性。在一个300行的头文件里,在99行这样低调的位置里,静静的插上了自己的方法,还在上面认认真真的写上了准确的注释:

1
2
3
4
5
/*扩展*/
-(void)setDDCImageWithURL:(NSURL *)url
         placeholderImage:(UIImage *)placeholderImage
                  success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
                  failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;

扩展个头啊!你加在人家的头文件里你说你是扩展,谁信?

这种改动遍地都是,特点是极其低调,难以察觉,甚至 TTTAttributedLabel 这种 UI 库也不能避免:改了 init 为了统一字体和颜色。。。

你说这代码,谁敢改?

我还曾经单纯的想给项目加上 Cocoapods 更新一下第三方库,现在想想,Naive。等以后写到新的独立模块的时候再说吧。

正所谓:

项目勤用三方库,随意穿插改无数。
即使类库有更新,试问代码谁维护。

第六回:单个对象多职责,悲伤逆向流成河

在聊天模块有这样一个类:ChatModel ,简直就是个多面手。

上能和服务器聊天,上传聊天消息同步聊天记录:

1
2
3
4
5
6
- (void)reSendMessages;
- (void)receiveSecretaryMessage:(MessageEntity *)msgEntity;
- (void)deleteMessagesByUserInfo:(UserInfo *)user;
- (void)setAudioMessageBePlayed:(AudioMessageEntity *)audioMessage;
- (void)sendBubbleReplyWithCallMessage:(CallMessageEntity *)callMessage;
- (int)saveMessage:(MessageEntity *)message;

下能做本地缓存管理,增删改查样样精通:

1
2
3
- (void)saveCacheMsg:(NSString *)msg UserMd5:(NSString *)md5;
- (NSString *)loadCacheMsgWithMd5:(NSString *)md5;
- (void)clearCacheMsgWithMd5:(NSString *)md5;

至于什么弹窗提醒,上传进度,完成提示,亦是轻松拿下。

以至于你改着改着不知不觉都会走到这里,因为它处理了太多太多的业务逻辑,每次 DEBUG 追杀断点回到这里,都像是一场久别重逢时的相遇,似曾相识。

正所谓:

一人做事一人当,切忌都往类里装。
开发人员干的爽,维护人员很受伤。

第七回:产品突增新功能,一行代码变大神

有时候需求来也匆匆去也匆匆,让人猝不及防。比如一个简单的登录逻辑:

1
2
3
4
5
@interface LoginModel ()
@property (nonatomic, strong)NSString *tcpURL;
@property (nonatomic, strong)UserInfo *offlineCallUser;
@property (nonatomic, assign)VersionStatus versionStatus;
@end

突然发现需要在版本更新的时候多个 API 检查,简单,加个 BOOL ,需要的时候设置成 YES 就行:

1
@property (nonatomic, assign)BOOL isShowVersionUpdate;

但是这个功能在 About 页面又有点改动,简单,再加个 BOOL 就行:

1
@property (nonatomic, assign)BOOL checkVersionFromAbout;

然后如果已经显示了注册页面又要少一些请求,行,那再加个 BOOL 值:

1
@property (nonatomic, assign)BOOL isRegisterShow;

得了,这代码只有你能懂了:

1
2
3
4
5
6
7
8
@interface LoginModel ()
@property (nonatomic, strong)NSString *tcpURL;
@property (nonatomic, strong)UserInfo *offlineCallUser;
@property (nonatomic, assign)VersionStatus versionStatus;
@property (nonatomic, assign)BOOL isShowVersionUpdate;
@property (nonatomic, assign)BOOL checkVersionFromAbout;
@property (nonatomic, assign)BOOL isRegisterShow;
@end

想象一下实现方法里各种对 BOOL 标记的特殊处理,想象一下 N 个 if 嵌套的壮观场景。

心塞。

正所谓:

凡是都要听产品,各种业务催的紧。
天塌下来也别怕,逻辑清晰自然挺。

第八回:来了任务有委托,多写一行都嫌多

所谓悲哀就是,当程序员发现一个 delegate 就能访问上级的对象,于是便把各种需要通知上级的事情都放在了委托方法里,尽管这些事情与委托本身无关,但是为了实现功能已经不在意这些所谓的设计与美观。

一个简单的 @optional ,甚至可以用同一个 @protocol 获取到各种不同的上级对象,只需要每次调用的时候加个 respondsToSelector 就行了。写上十几个可选方法,取一个通俗的委托名,比如 MyDelegate ,然后如果你持有了我但是我还想调用你的方法, so easy ,把你的方法扔到 MyDelegate 即可。

此时的代码便已经不再是一件艺术品,而只是一个平凡普通、毫无生机的花瓶了。

小结

原本还是挺欢快的吐槽,突然就不想写了。

看着以前的人写的代码,不禁有些凄凉。

在项目里用尽了各种低级下流的手段,只为了实现自己的业务。

这是对艺术的侮辱。

<think>嗯,用户问的是11408怎么安排备考,首先我得确认11408是什么。11408应该是考研的科目代码,通常指的是计算机专业的统考科目,包括政治(101)、英语一(201)、数学一(301)和计算机学科专业基础综合(408)。用户可能对考研科目代码不太熟悉,所以需要明确这一点。 接下来,用户的需求是安排备考计划,尤其是针对数学一和408这两门难度较大的科目。需要分析用户可能的背景,比如是否跨考,基础如何,时间安排等。用户可能在刚开始准备,对如何分配时间和资源感到困惑。 首先,我需要考虑数学一和408的考试内容和难度。数学一涵盖高数、线代、概率论,内容多且深,408包括数据结构、计算机组成原理、操作系统、计算机网络,四门专业课,同样内容庞杂。这两门都需要大量时间投入,所以时间分配是关键。 然后,用户的真实需求可能是希望得到一个高效的时间安排表,兼顾各科,尤其是数学和408。可能还存在一些隐藏的担忧,比如如何平衡复习进度,避免某一科拖后腿,或者如何在有限的时间内掌握大量知识点。 接下来需要分阶段规划,比如基础、强化、冲刺阶段,每个阶段的重点和时间分配。数学一和408都需要长期积累,所以要强调基础的重要性,尤其是跨考生可能需要更多时间打基础。 另外,用户可能需要一些资源推荐,比如教材、习题册、网课等,帮助其高效学习。同时,复习策略也很重要,比如如何做笔记,如何刷题,如何处理错题,如何模拟考试等。 还要考虑用户的时间安排,比如每天学习多少小时,各科的时间占比。数学和408可能需要各占30%左右的时间,政治和英语相对少一些,但也不能忽视,尤其是英语需要长期积累。 最后,要提醒用户注意调整计划,定期自测,查漏补缺,保持心态稳定。备考过程中可能会遇到挫折,需要坚持和适时调整方法。</think>**11408(计算机统考)全年备考规划——400+高分策略** **(数学一+408专业课深度整合方案)** --- ### **一、学科特性分析** | 科目 | 分值 | 核心难点 | 关键突破点 | |------------|--------|---------------------------|---------------------------| | **数学一** | 150分 | 高数证明题、级数收敛性 | 计算准确率+题型归纳 | | **408** | 150分 | 计组Cache映射、OS死锁 | 知识体系构建+真题复现度 | | **英语一** | 100分 | 阅读新题型、作文提分 | 真题精读+模板定制 | | **政治** | 100分 | 多选题、时政分析题 | 肖四肖八+keywords记忆法 | --- ### **二、阶段划分与时间配比** **总原则:数学与408双主线并行,日均学习时长≥10小时** ```markdown 1. **基础阶段(3-6月)** - 数学:40% → 张宇30讲+《660题》高数部分 - 408:40% → 王道单科书+课后选择题 - 英语:15% → 单词5500+长难句分析 - 政治:5% → 马原基础课(徐涛/腿姐) 2. **强化阶段(7-9月)** - 数学:35% → 李永乐强化班+《880题》综合训练 - 408:35% → 王道强化课+历年真题分类突破 - 英语:20% → 2010-2020阅读精翻+作文框架 - 政治:10% → 肖秀荣1000题+腿姐技巧班 3. **冲刺阶段(10-12月)** - 数学:30% → 近15年真题+李林6+4模拟 - 408:30% → 真题套卷训练+错题重刷3遍 - 英语:20% → 作文模板实战+新题型技巧 - 政治:20% → 肖四背诵+时政热点汇总 ``` --- ### **三、数学一&408协同攻坚策略** **1. 数学一核心模块优先级** - **必拿分模块(120分基础)**: ```markdown · 高数:极限计算(每年必考)、二重积分(极坐标变换)、微分方程 · 线代:特征值应用、二次型标准化 · 概率:二维分布函数、参数估计(矩估计/MLE) ``` - **冲刺高分模块(30分压轴)**: ```markdown · 中值定理证明(罗尔/拉格朗日) · 级数求和(傅里叶级数展开) · 随机过程(马尔可夫链) ``` **2. 408四门科目突破法则** - **数据结构(45分)**: ```markdown · 重点突破:树与图的应用(哈夫曼编码、最短路径) · 算法题:每天手写1个代码(排序/查找/动态规划) ``` - **计算机组成原理(35分)**: ```markdown · 必会考点:Cache组相联映射、浮点数运算 · 难点突破:指令流水线冲突解决方案 ``` - **操作系统(35分)**: ```markdown · 核心机制:虚拟内存页面置换算法(LRU/CLOCK) · 综合应用:哲学家进餐问题变形题 ``` - **计算机网络(35分)**: ```markdown · 协议分析:TCP三次握手/四次挥手状态转换 · 计算专题:子网划分与CIDR地址聚合 ``` --- ### **四、每日时间表示例(强化阶段参考)** | 时段 | 任务安排 | 注意事项 | |-------------|-----------------------------------|---------------------------| | 7:00-8:30 | 英语单词+政治keywords记忆 | 利用艾宾浩斯记忆法 | | 8:45-11:45 | 数学强化训练(专题突破+错题总结) | 严格限时,模拟考场压力 | | 13:30-16:30 | 408真题精研(1套卷+错题分析) | 重点关注算法设计题 | | 16:45-18:00 | 英语阅读精读(2篇+长难句翻译) | 标注出题点与干扰项特征 | | 19:30-21:30 | 数学/408交叉复习(薄弱环节补漏) | 使用康奈尔笔记法整理 | | 21:45-23:00 | 政治选择题+当日知识复盘 | 建立错题本(按章节分类) | --- ### **五、关键提分工具包** 1. **数学一**: - 《李正元复习全书》(证明题专项) - 真题分类汇编(1987-2023年按考点整理) - 公式速查手册(随身携带版) 2. **408**: - 王道真题考点分布图(2010-2023统计表) - 自主命题高校真题精选(浙大/中科院等) - 思维导图软件(XMind梳理四科知识体系) 3. **效率工具**: - 番茄Todo(严格执行25分钟专注周期) - Anki记忆卡(自动推送重难点知识) - 错题扫描APP(快速建立电子错题本) --- ### **六、避预警** ⚠️ **数学一致命误区**: - 沉迷偏难怪题(如微分几何应用)忽略基础计算 - 过度依赖答案(看到答案"显然可得"就跳过推导) - 忽视选填题训练(2023年选填每题5分,错4个直接丢20分) ⚠️ **408常见陷阱**: - 算法题只动眼不动手(实际写代码时漏洞百出) - 混淆相似概念(如进程切换vs模式切换) - 低估历年真题价值(2023年考点90%与往年重复) --- **终极建议**: 1. **数学与408每周必须模考**(周日上午数学,下午408) 2. **建立双科目错题关联库**(如离散数学与数据结构联动) 3. **12月冲刺期重点抓政治**(肖四大题背诵量会超预期) **立即行动**: - 下载2024考研大纲对比表 - 制定个性化月计划表(预留10%弹性时间) - 加入高质量备考社群(推荐王道论坛/灰灰考研) 坚持按此规划执行,11408总分400+完全可期!最后6个月,你与梦想的距离只差一个科学的计划!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值