过早的优化是万恶之源

这两天,我做了两件事:

  1.重构了系统某个模块的部分代码:

  花了一天时间,一个6k多行的java文件,搞到4k行加若干个类文件,恕我能力有限,后面的实在重构不下去了,那是一种3个domain属性名几乎一样100多个字段但是却用同一个copy了三遍的方法来处理的欲哭无泪,那是一种使劲滚鼠标滚轮都滚不到一个方法尾部的绝望(100多个字段的几个类属性equals来,equals去,get来,set去的,这样类型的方法有那么五六个,你说能不多吗)......

 

  2.做了一个日志处理的小工具:

  客户要求把日志里面记录的一些东西整理出来发给他们业务人员分析,有若干个日志文件,20多m一个,我本来打算一个一个Ctrl+F,Ctrl+C,Ctrl+V的,但是后来想到自己能否更高效去处理这件事,毕竟自己出来工作两年了,很多时候做一些重复的事情,这样不会有提高,所以我决定用自己写个处理日志的小工具

  把一个log文件里面的内容按关键字找到然后解析相应字段然后格式化写到excel里面去,

  我把日志简化一下,其中一个片段样子大概是这样的:

    field1:=value1

    field2:=value2

    field3:=value3

    ......

    ......  

    ......

    xxxxxxxxxxx:field3:value3 field4:value4 field5:value5 

 

  我们需要取得field1,field3,field4,field5名字以及值 

  field3-field5很好办,直接定位"field3:"所在的行,然后把这一行取出解析出来即可

  但是field1的值不是很好处理,我当时就想了最傻的一个办法:扫一遍文件解析出field3-field5,然后用field3的值再扫一遍文件找到field1的值,速度那个慢呀

  后来就想了一个稍微更聪明一点的办法,

  把

    field1:=value1

    field2:=value2

    field3:=value3

  封装成一个数据结构, 每一行用一个字符串来装,在扫描第一遍的时候,就把这个数据结构的用List存起来,假设为TempList,把field3-field5作为一个数据结构存进一个list,这样的话 我处理之前得到的field3-field5这个List和这个TempList,内存操作,速度提升很明显。

 

收获和教训:

  1.做这两件事的一个大背景是在版本正在开发的过程中,我写的版本计划预留了一部分时间去应对需求变更,但是自己却花了多余的时间做了第一件事,吃力不讨好,最后还没动需求要做的东西,重构了半天,代码还是如此的让人绝望,现在才深刻体会到,看别人写的优秀代码,是对自己的一种提高,看别人写的很恶心的代码,对自己也是一种提高:告诉自己不要这样写。

  2.效率这个东西,是很重要的,特别是在做项目的过程中,如果能尽量让机器帮忙解决的事情,就不要人工去做,而对于程序员来说,尽可能多的写一些小工具(当然我技术不好,可能写个工具的时间都要影响进度-_-#)来帮忙解决一些手工问题:比如之前在每个版本打分支的时候都需要建立项目的空目录,然后申请相应SVN权限,然后把空目录删除,将上一个版本在svn上copy to 一份出来作为开发,因为工程比较多,这个建立空目录的过程很繁琐,所以我就写了一个cmd脚本来运行建立新目录,这样每次打分支之前运行这个脚本即可,省去了一些copy/paste操作。

  3.项目开发的过程中,核心的技能就是尽量精确的评估,如果一件事,你没有评估就贸然去做,是一件非常可怕的事情,如果让我重新选择,我不会拿上班的时间再去重构这部分代码,我会先把任务完成,完成的基础上,下班后,在Intern version(for practise)上练习重构。

  4.突然想到自己为什么要用这个标题。-_-# ,重构的这部分代码不是我写的,当我看到这样的代码的时候常常会特别愤慨地说当时为什么写这样难维护的代码出来,后来当我写这个小工具,回头看看自己曾经写过的那些一点都不亚于这种难维护的代码的时候,我明白了:在做项目的时候,特别是极度紧迫的时间里,解决问题才是最重要的。如果你效率极高,能力极好,脑海中各种模式烂熟于心,一看到一个场景立马可以构建出可重用,易扩展的代码,那无可厚非;但是对于我们这些普通小白码农来说,首先解决这个问题,有时间多自己再折腾折腾把。

转载于:https://www.cnblogs.com/greyzeng/p/4077732.html

子任务4:确定程序所需的数据结构 经过以上分析可知,为了得到公历日期对应的星期、农历日期、节气、节日,程序需要预知以下数据: 1月1日的星期:weekday_2025; 1月1日的农历日期:lunar_start_date_2025; 每个农历月份的天数:lm_days_2025; 是否有农历闰月。若有,是几月:lm_leap_month_2025; 每个节气对应的公历日期:solar_terms_2025; 每个节日对应的公历日期或农历日期:feasts。 查阅得到这些信息,以合适的形式写进程序中即可。(把数据写进程序,称为数据“硬编码”,是比较糟糕的做法。但作为最初的探索,却是最快能够看到结果的。后续将分离程序数据,解决数据“硬编码”的问题) 其中,除了weekdayfeasts之外,其余都是每年有一份数据。其中,下一年的weekday可以轻而易举地按照上一年的weekday计算得到,因而只需要保存其中某一年的weekday,而不需要每年都保存一份。 节日feasts年份无关,比如每年的国庆节都是10月1日、春节都是正月初一,因而也无需每年都保存一份。 其余数据,均年份有关,需要每年保存一份。 日期表示 日期,是程序中的基本概念,完整的日期包含公历日期、农历日期、星期、节气、节日等多项成员。比如,可以表示为: struct u_date_t { short year; char month; char day; }; struct full_date_t { struct u_date_t solar_date; struct u_date_t lunar_date; char weekday; char solar_term; char feast; }; 这样做当然是可以的,但可能使程序代码显得冗长。由于T1任务中并没有用到full_date_t结构体的情形,为使程序代码简短,暂不考虑这样表示日期,但保留struct u_date_t结构体作为公历日期农历日期统一的表示方式。 关键是要解决第2步中“预知数据”的表示及存储。 计算星期几所需的数据 每年1月1日是星期几,可以从1970年1月1日是星期几计算得到。因而,只需要存储weekday_1970即可。 const char weekday_1970 = 4; /* 1970年1月1日是星期四 */ 节日对应的日期只需要月、日,可以表示为: const struct feast_t { enum {SOLAR, LUNAR} type; struct u_date_t u_date; const char * name; } g_feasts[] = { {SOLAR, {0, 1, 1}, "元旦"}, {LUNAR,{0, 1, 1}, "春节"}, {SOLAR, {0, 10, 1}, "国庆节"}, {LUNAR, {0,5,5}, "端午节"} }; 更多的节日按同样格式加到结构体数据中即可。借用之前定义的struct u_date_t结构体时,此处用不到其中的year成员,初始化为用不到的0即可。 每年需要单独存储的数据 以下4个数据每年需要单独存储: 1月1日的农历日期:lunar_start_date_2025; 每个农历月份的天数:lm_days_2025; 是否有农历闰月。若有,是几月:lm_leap_month_2025; 每个节气对应的公历日期:solar_terms_2025; 可以放到同一个struct中: struct lunar_info_t { struct u_date_t lunar_start_date; char lm_days[12]; /* 12个农历月每月的天数 */ char lm_leap_month; /* 农历闰月的月份序号,无闰月时为0 */ char solar_terms[24]; /* 24个节气对应的公历日期 */ } g_lunar_info[130] = {……}; /* 从1970~2099共130年 */ 完成以上两个struct之后,发现u_date_t.year到处都用不到,删除该成员,相应修改初始化数据。注意:这一步必须要等到最后再做,不要过早地下结论。这旧工作属于“优化”的范畴,过早优化万恶之源。首先按部就班、不厌其烦地完成可以运行的程序,绝不在程序还不能运行之前开始优化,才是编程的正确做法。 基础数据 除了参计算的数据之外,星期、农历月份日期、节气在程序内部都使用整数表示,而输出时都需要转换成字符串,这类数据统一放到基础数据中。 const stuct base_info_t { const char weekday_1970; const char * wd_name[7]; const char * lm_name[12]; const char * ld_name[30]; const char * st_name[24]; } g_bi = { .weekday_1970 = 4, .wd_name = {"星期日", "星期一", "星期二","星期三","星期四","星期五", "星期六"}, .lm_name = {"正月", "二月","三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "腊月"}, .ld_name = {"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"}, .st_name = {"小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分","寒露", "霜降", "立冬", "小雪", "大雪", "冬至"} }; 有了如上分析和数据基础,可以得到能够正确计算出每天是星期几,以及2025年每天对应农历日期的程序。 写出完整的C语言程序代码。
最新发布
06-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值