Shenlvmeng's Blog

Blog


  • 首页

  • 归档

  • 标签

  • 搜索

2020回顾暨2021展望

发表于 2021-01-05 | 分类于 日记 |

2019年写下第一篇总结的时候,也未曾想到,这会成为一种一年一度的仪式,甚至能吸引到听众。但既然开始了,最好也能坚持下去。

如果说2019充满意外的话,2020只会是加大分量。不论是喜悦还是痛苦,2020留下的印记都格外得深一些。整体来看,由于遇到了一些预料之外的事情,在自我提升上向陌生方向多走了一些,不知是好是坏。

2020回顾

内在素质上,阅读技术非技术方面的书籍完成5本,小说6本。基本完成任务。

  • Go语言入门学习
  • 《程序员思维修炼》—— 思维方式和学习技巧
  • 《经济学原理》 - 宏观经济学原理笔记
  • 《软技能 —— 代码外的生存指南》书摘
  • 重构 —— 代码的实用性与艺术性

整体还是在东看看西看看的阶段,其中《程序员思维修炼》一书对思维方式的介绍补足了自己的知识体系中方法论的部分。《软技能》一书启发了在理财方面的一些认识。

大多数的书还是看了又忘,忘了就再看看总结,然后再淡忘。这个过程中,留在知识体系里幸存的部分并不多。尤其是编程相关的书籍,还是需要靠实践做项目来巩固所看的内容。没错,说的就是《Go语言入门学习》。

个人形象上,作息时间基本达到预期计划。但由于出现了新爱好(调酒),买衣服的计划被长期搁置。工装裤和卫衣还是去年那些,果然这两样买再多都不够。体重略有下降,回到80。算是基本完成目标。发型在推平后,又往偏分的方向留了起来,和此前的侧背区别不甚大。短发在身边朋友的反馈里居然还不错。

社交上,丢失和主动放弃了一些朋友,大多是三观不合或者事业变动。在和朋友的沟通交往中,更偏向主动。不过长期如此,还挺累的。热情不用更热情了,倒是应该更加增大交友面。有试图发展亲密关系的朋友,在对象上有过努力,也同时认识到很多道理,此处略去。

生活情趣上,在骑车、拉琴、看电影上仍旧投入较多业余时间,其中骑车的设备也一直还是那辆老旧的山地车。拉琴和看电影上也没有什么投入。同时,发展了喝酒和调鸡尾酒的爱好。在冰箱中屯了很多,对基酒和调酒也有了些认识。骑行上,因为圣僧的工作变动,离开了北京,一位年轻的同事成为了新的骑友。百里画廊未能成行,但是青海湖成功成行,也是一次难忘的经历。旅行上,疫情原因日本没去成,年末去了广州,吃了好吃的一本满足。拉琴上,一直也有练习,有能熟练演奏的曲目,不过都还需要看谱演奏。另外,也在公司内做过相关分享。新爱好上,看了第一次话剧,livehouse一直没遇到喜欢的乐队,未能成行。另外因为厨房卫生问题,在家做饭频率下降,反而提高了探店的频率。整体看,生活还蛮有趣味。

工作事业上,发展尚可,背靠还不错的项目组,也遇到了很多挑战,有了带小方向的机会,在团队建设上也开始有了思考。不过进步速度在下半年有所减缓,注意力有些偏移。希望在下一年能调整过来。

简单说几句

  • 积累太过理想化书面化,积累些现实点的东西,不是坏事
  • 穿衣上,裤长是最严重的问题
  • 要少喝酒,小酌小酌
  • 坚持作息和三餐,坚持骑行登山游泳轧马路
  • 要能清醒思考个人价值和现实价值
  • 一段长久的亲密关系应该是相互成就而不是相互束缚的
  • 爱合理分布在亲人、伴侣、朋友身上
  • 事业上决断力要提高,还要画饼能力,越大越好

2021展望

OK,又到了flag时间。吸取前两年的经验,目标不宜太明确,往往有意外惊喜。

  • 内在:看完囤积的4本业务书籍和10本左右小说
    • 再寻找一项和前端覆盖率类似的技术点去探索突破
    • 能清醒地评估个人价值,先知己
    • 回顾过去几年积累,完善知识体系
  • 外在:尝试新风格,保持健康,坚持运动
    • 坚持吃早饭和早睡
    • 增加锻炼频率
    • 发型尝试
    • 基本款补齐(同去年)
  • 情感
    • 平衡爱的收入和支出,更有自信
    • 能给一个人未来
  • 生活
    • 寻找一些提高生活幸福感的小东西或者经验
    • 保持室内干净卫生
    • 必要的旅行
    • 固定的户外长途骑行
    • 尝试新的菜式
    • 坚持拉琴、电影、探店
    • 至少一次livehouse
  • 事业
    • 思考职业规划和发展路线
    • 考虑落脚城市、医疗、教育等现实因素
    • 也去考虑父母的未来生活质量

就这么多吧,流水账短点为妙。诸位明年见~

Bye~

记青海湖骑行

发表于 2020-10-06 | 分类于 游记 |

随便写写。旅程中的大多数美好,事后回忆,原来都在造化中。

序:准备阶段

这次旅行本该在去年国庆成行,由于假期有限等种种原因delay到今年这个长假。又碰巧赶上疫情和中秋带来的额外假期,于是7、8月便早早和档期向来紧张的圣僧约好。圣僧和我本是隔壁宿舍关系,从3年多前的一次结伴骑行结缘,是我的长期骑友。他是个旅行达人(友链一波:肥叉烧),身在外企,有钱有闲,经常出游,经验丰富。正巧这次碰上疫情,国外无处可去,和我定好日程后,三下五除二便把攻略搞定。和他一起出游真是省心。

Day 1:银川

出于下面多个因素考虑(其实主要是第三项),我们第一天先出发去银川。

  • 假期时间充裕
  • 慢慢适应高海拔
  • 中转机票更便宜
  • 凭借圣僧的会员,中转免费送一晚住宿外加去市区的大巴券

因为这次是从大兴机场出发,还是8点半的飞机,早上5点就得起床。

清晨的知春路口

我们在机场值机柜台碰面,托运完行李时间已经不早了,于是直接就安检进站。安检中还没收了我的修车工具(😢)。这也是这一路意外离开我的第一样东西。突然到我都没拍张照给它留个纪念。

进站后,借助圣僧招行信用卡会员,一起在VIP休息厅吃了个早餐,条件还不错。

VIP休息厅视角

9月26号的银川天气不错,我们住宿的酒店——西港航空饭店距离银川河东机场非常近。酒店建筑整体很新,周围被各种绿化围绕,完全感觉不到在西北。另外房间很大,由于远离市区,环境也很安静。加上是中转免费送的,算是我们整个旅程中最满意的住宿体验了。

西港-1

西港-2

在房间里稍作休息,我们步行到机场坐大巴前往市区,大巴券25元一位,我们使用的中转服务的免费大巴券直接乘车。大约1小时车程,我们在终点站鼓楼下车便进入了市中心。

鼓楼

稍微逛逛,我和圣僧很快就发现了多不胜数的蜜雪冰城,几乎不见其他知名品牌,剩下的也都是没听过名字的小牌子。在竞争上,蜜雪冰城比上有其很能打的性价比,比下又有标准化保证。4元的柠檬水、5元的奶茶、2元的圆筒冰淇淋。天哪,这也太香了。蜜雪冰城也将成为我们后面旅程中的一大精神寄托,按下不表。

蜜雪冰城

作为回族自治区的省会,菜单中自然没有猪肉,取而代之的是各种羊肉。从鼓楼步行街向西走过几个路口,我们惯例性在地在邮局寄了明信片。随后在旁边的迎宾楼吃了午饭,尝了下号称特色的手抓羊肉。这么一盘98元,没想象中好吃,吃了三分之一就有点腻了。最后打包给圣僧当了晚餐。

手抓羊肉

吃饱喝足,下个目标是带些伴手礼。宁夏的枸杞是比较出名的,其中以中卫的为最优。枸杞分红枸杞和黑枸杞,都没有明确的药用价值。但是日常保健还是有用的,号称能补气虚,很适合阳气虚弱的男性。黑枸杞据说劲儿更野一点。稍微做了下功课,我们在超市一人来了2斤,一斤75元。事后看,这个价格似乎有些上当,建议各位小买怡情即可。

银川城区内的共享单车似乎都是电动车,不论是青桔还是小蓝,还是美团单车。在一天的观察下,只注意到凤毛麟角的人力单车。这到底是因为当地人自行车技术很烂还是电动车驾驶技术很普及?挺有意思。

共享单车

天色渐暗,在人民公园感受了城市氛围后,我们乘坐大巴回到西港航空饭店,为第二天前往西宁做准备。

Day 2: 西宁

西宁相比银川更有省会的感觉。不同于银川的回族居多,西宁有着比较明显的藏族气息,藏民也很常见。高海拔的强烈紫外线下,大多数人都是黝红的脸。由于第二天要坐大巴前往西海镇,我们这一天住在汽车站旁边的如家,在市区中处于偏东郊的位置。不出意外,楼下又是一家蜜雪冰城。

酒店

西宁城区内有湟水自西向东流过,我们下午先是打车到了河边的中心广场,类似北京的元大都城垣遗址一样,不过明显更大且更有层次,湟水河宽度近似海河。在河边坐也好,走也好,感觉都是很不错的。下午3点,气温十余度,在河边的长椅上,一直都能看到飞机在高楼的天际线上划过。

西宁海拔约2100左右,处于多个山脉中的河谷地区,适宜建设城市的面积不大,只有大概一个十字形状的区域。所以城区中的楼房都格外的高,且能看出一些地势起伏。整体感觉,似乎来到了小号版的重庆。和重庆一样,这里看不到共享单车。

城市景观

不过从一些城市的角落,还是能瞥见藏在深处的旧工业时代的厂房气息。

旧厂房

我比较偏好用随便走走四处看看的方式感受城市的风格。下午我们从中心广场绕过力盟商业区,再穿过九龙城寨般的商业巷大世界,从人民公园门口向回走,最后又回到颇具人气的力盟步行街。不能免俗,吃了顿呷哺呷哺。

呷哺呷哺

Day 3: 西海镇 - 种羊场

里程:48km

去西海镇的车票我们是提前一天买好的,25元。但因为游客不多,其实也可以当天早上买。从火车站背后上京藏高速,一路穿过湟中区、湟源县、海晏县就到达了最终骑行的出发点西海镇,全程约2小时。租车上,我们早已提前和当地租车师傅约好,6天行程,租车500元,外加解决住宿700元(对租车店老板安排的住宿不要抱太高期望)和押金500元(结束骑行后退还),一共1700元。

西宁到西海镇

西海镇是海北藏族自治州的州首府,不过却意外的荒凉,街道两边政府部门倒是周正齐全,基础设施也是一应完善,可是就是人迹稀少,连车都没几辆。我们下车后已经10点,第一天尚有40多公里的路程要骑。我们调试好车辆,装好驮包,穿戴好装备,擦好防晒(这个十分重要),简单吃了个饭就出发了。

出发合影

沿着刚察路直走,穿过和G213国道的路口,就上了环湖东路。沿着环湖东路直走就可以达到第一天的目的地——湖东种羊场。路线也是相当简单。

路牌

初见丘陵和草原,配合着壮观的云层,还是很有新鲜感的。

草原1

草原2

山丘1

第一天的路并不像路书中那样全是平路,相反上下坡并不少。幸运的是,路边的景观稍微减缓了骑行的疲惫感。

上坡1

上坡2

穿过和G213国道的分岔路口后,我们离湖越来越近了。

996

路牌

随着湖水越来越近,金银潭和沙岛上起伏的沙丘却是也越来越显眼。湖边的荒漠化土地是我预先没想到的,据说是气候原因导致。但从沿路看到的各种牛羊来推断,和过度放牧可能也有些关系。

沙漠1

牦牛1

穿过金银滩沙漠区,是一个大下坡,下坡后路两侧又逐渐恢复了植被和河流,看起来顺眼多了。

大下坡

绿地

青海湖边地广人稀(整个青海除了西宁和海东应该都是地广人稀),除了风声,路两旁十分宁静,若是没有毒辣的紫外线,实在惬意极了。

车1

再往前骑数公里,终于到达种羊场。这并不是一个镇或县,顶多是围绕湖东种羊场的一个聚落。住宿环境自然十分感人。卫生糟糕,门窗都可以从外面打开。具老板所说,这里民风淳朴,姑且只能信了。

种羊场住宿

幸好有炕锅羊肉和壮观的落日场景可以抚慰。

炕锅羊肉

落日1

落日2

青海湖周围海拔3200到3400,昼夜温差较大,太阳一落山,气温就比较冷了。种羊场也无甚可逛,我们直接倒头就睡,洗漱更衣直接放弃。只期待第二天住宿能好点。

Day 4: 种羊场 - 江西沟

里程:55km

第二天一早我们吃了点买好的干粮,擦了防晒就直接出发。种羊场实在没什么好留恋。青海湖环湖的路都很直,两侧要么是无边的草原,要么是起伏的山丘,要么是看不到头的湖面。以至于路也看不到终点,似乎永远都骑不到头。

路1

不过在骑行中,能察觉到远处的村庄、山岭、景观一点点靠近,还是蛮奇妙。

路2

路边是牧民们的牛羊,似乎和内地的品种并不相同。牦牛们都很沉默,羊们也是,我蹩脚地起个头,它们也只是懒懒地抬个头望向我,依旧沉默。马儿们有的自由吃草,被人看管的则用来招徕游客骑行创收。

牛

羊

骑过错果,便告别了环湖东路S207,来到G109国道,相比环湖东路,国道上的车辆明显多了很多。

错果

路牌2

从环湖东路和G109的交叉口到二郎剑景区,靠湖一侧都有维护良好的辅路,路面起伏不大,还有成片的油菜花可以欣赏,油菜花都不高,游客在其中拍照能露出脑袋,从车上看颇有趣味。

油菜花

路的另一侧是连绵的不知疲倦的山丘,它将一路陪伴我们告别G109国道。

山丘2

临近二郎剑景区有可以直接接近湖面的地方。这是一路第一次能亲近湖水的机会。

青海湖

在二郎剑边的中石油稍作休息,是一路枯燥的景观,16km后便到达终点江西沟。令人欣慰的是,住宿环境有了些微的改善。

江西沟住宿

Day 5: 江西沟 - 黑马河/茶卡

里程:48km

这一天的里程虽然不长,却是环湖几天中,最疲惫的。原因是没有止境的逆风。一路上,景观和前一天无异,枯燥的山丘和草原,连湖面也不太能看见了。因为恼火的逆风,我甚至都没心情抬头看看路两旁的风景。

也许是因为大风把碎云都卷走,天上的云倒是挺好看。

云1

云2

我大约提前圣僧1个小时到达,考虑到高原和糟糕的风向,圣僧临时修改计划,将第二天的茶卡盐湖之旅提前,把本来一天到达刚察县的计划拆成石乃亥 - 刚察县。这一决定不仅让我们看到了茶卡盐湖上的落日,也极大提升了后两天的骑行体验。

黑马河

黑马河位于G109和环湖西路S209的交叉口,前往茶卡、鸟岛,大西北自驾环线、环湖骑行都要经过这里。本来是发展不错的一个小镇。近些年考虑到环保因素,拆了大多数建筑,统一由政府管理建设,道路管道也大兴土木整修,目前看起来完全感受不到当地人所说当初的繁华。

我们运气不错,碰巧民宿老板要前往茶卡办公事,在圣僧下午3点到达后,我们搭了个便车去往茶卡(来回两人300元)。走G109去茶卡镇要穿越橡皮山,最高海拔3800m,且单程80km。对于骑行来说不太现实。老板比较健谈,一路和我们介绍了青海湖的旅游发展以及周边地理人文,挺有意思。

橡皮山1

橡皮山2

茶卡盐湖的风景十分看天气。晴天无风的天气下,才有天空之镜的感觉。我们去的那天虽然晴空万里,不过风力较大,差不多夕阳落山时,西风终于转弱,得以让我拍到下面的景象。

夕阳3

夕阳4

盐湖门票原价60,对青海、湖北、浙江籍游客免票。小火车单程50,车速和步行差不多,没有强需求可以不做。小火车沿着一条向湖区深处的路一直开到最里面,大约30分钟。路的西边湖水较浅,许多已蒸干出盐巴,还能看到湖盐厂的旧铁路和新厂址。许多游客穿着租赁的胶鞋在水面嬉戏。

盐湖游客

搭配雪一样的湖盐,有种北极村的感觉。

"北极村"

坐车回到黑马河时已经晚上9点了,晚饭是牦牛肉串 + 牛肉面,巴适得很。

肉串加牛肉面

Day 6: 黑马河 - 石乃亥

里程:39km

没有了恼人的逆风后,这一天好骑多了(再加上里程短,应该是环湖最轻松的一天)。骑出黑马河镇,就和G109国道告别,上了环湖西路,车辆明显稍多了,整体体验大大提升。经过一段笔直的路程,可以绕到离湖不远的地方,接下来的一路也都如此,还能时不时看到自驾游的游客在路边拍照。

湖边

等接近石乃亥后,我们便离湖越来越远。经过一个小上坡,便能远远看到石乃亥乡的轮廓了。

小上坡1

小上坡2

石乃亥不大,基础设施倒是挺完善。由于到得比较早,我们很轻松吃了个土火锅作为午饭。土火锅里面有牦牛肉和各种素菜,价格145,还算划算。我们大快朵颐了快1个小时,最后也没吃完。

土火锅

Day 7: 石乃亥 - 刚察县

里程:78km

骑出石乃亥约20公里,我们告别了海南共和县,来到海北刚察县境内。一如往常又是广袤的草原和起伏的山丘。骑过关闭的鸟岛,就来到了湖边的最后一段路。

湖羊

站在环湖东路的末尾处回头望,能看到最后一片湖面的波光粼粼。

波光粼粼

从岔路口右拐上G315国道,会贴着青藏铁路走一段。之后越过新修的西和高速便进入县城内。

岔道

铁路1

铁路2

刚察县虽然只是个县城,但是热闹程度和城市美化程度一点不亚于西海镇,甚至更甚。

刚察县

县城里的藏城电影院也在营业,虽然放映厅很小,还没有大学大教室大,但两人包场看《我和我的故乡》的体验还不错。

刚察电影院

吃厌了羊肉,我们晚饭在一家成都冒菜馆解决了晚饭,能有吃菜自由的感觉真好。

冒菜

另外,刚察的旅游厕所做的是真不错,体验比北京的管理公厕都要好。

刚厕

Day 8:刚察县 - 西海镇

里程:90km

最后一天离湖就很远了。出刚察县先是一个大上坡,接着几乎一路平路骑28km可以到达哈尔盖河边的哈尔盖镇。

刚察县上坡顶

在哈尔盖中石化稍作休整,沿着315国道再骑20km到达甘子河乡,开始最后一个长坡,从海拔3200m来到3415m。

哈尔盖车站路口

G315-170km

从这个坡顶一个俯冲下来穿过西和高速,便从G315回到G213国道。这一段逆风很大,由于修路,大车也很多。它们开过的同时,尘土飞扬,恨不得把自行车都给吸进去。

G315下坡

在一段艰辛的骑行后,我们来到修路的终点,也是整段路的最高海拔3445m,接着一路下坡,20km后在G213的拐弯处,西海镇已经越来越清晰。

骑行结尾

我们最后还了车,又寄了明信片。在西海镇停留了最后一天。这里作为海北藏族自治州首府,各种政府部门和基础设施完备齐全。就是人迹稀少。偌大的跳广场舞的活动中心也没个人影。

海北藏族自治州文化活动中心

夜晚了,路边的住房都亮起灯,仿佛又回到当初两弹一星时期建立原子城的岁月。

原子城夜景

Day 9/10: 西海镇 - 西宁 - 北京

最后一天,我们回到西宁。重回城市的感觉真好,标准化和工业化给人太饱满的安全感了,躺在床上,回想起这为期6天的骑行,尽管风景很原生态很美好,但这也是以牺牲了工业化和标准化为代价的。除开住宿环境,缺少便捷的物流和交通,让沿途小镇的餐饮费物价居然比在西宁高。离开西宁前往西海镇前,我们恐怕没有预期到,以前毫不在意的蜜雪冰城和德克士居然成为了一种奢求和精神寄托。也许,人们都是图个新鲜,享受惯了工业化城市化带来的福利,居然也会想吃吃贫瘠和原生态的苦。

经过此次“艰苦”的骑行,圣僧说他心心念念的川藏线骑行也要好好考虑考虑了,可能磨练人的不是骑行本身,反而是沿途令人生畏的住宿环境。我们脸上和腿上的晒伤需要时间痊愈。不知道,圣僧心理上的畏惧又需要多久痊愈。

–END–

重构 —— 代码的实用性与艺术性

发表于 2020-08-17 | 分类于 思考 |

MF的《重构》一书算是程序设计书籍的经典了。其中对于重构的认识和剖析深入浅出,提纲挈领。对于有一定编程经验的人来说更是如虎添翼的帮助。下面我尽量在不贬损原意的基础上,用自己的思路和语言进行适当的总结。

序 & 前言:重构的再认识

开篇名义,还未进入正文,书从序和前言开始,便不自觉间流露着真知灼见:

  • 重构是不改变软件可观察行为的前提下改善其内部结构。
  • 重构需要你维护一份“坏味道”和重构手段的对应
  • 设计前期使用模式通常会导致过度工程
  • 代码总将随着设计者的经验成长而进化

样例:感受重构

任何一个傻瓜都能写出计算机理解的代码。但唯有优秀的程序员才能写出人类能理解的代码

代码被阅读和修改的次数远多于被编写的次数。尽管代码在机器中运行时,机器并不会嫌弃代码丑陋。但是代码总是要修改的,当我们打算修改系统时,就涉及到了人。人在乎这些。差劲的系统很难维护,如果很难找到修改点,程序员就可能犯错,从而引入bug。如果你发现你需要为程序增加特性,但是当前的代码结构让你不能方便达成目标时,先重构那个程序,再方便地添加特性。

当然,重构前一定要确认,自己有没有一套可靠的测试机制,因为你需要它来保证重构的基础要素:不修改已有功能。重构中,最好能以微小的步伐前进(这样能及时回滚)。在本章样例的重构中,体现了下面一些“好味道”:

  • 代码块越小,代码功能就越好管理
  • 好的代码应该能够清楚表达自己的功能,变量名也是代码清晰的关键
  • 用多态取代条件判断逻辑
  • 结构化风格相比过程化风格更易扩展也更好维护

原则

本章介绍了重构的一些原则和基础性认识。

  • 何为重构:不改变软件可观察特性的前提下,通过修改内部结构,提高其可理解性。通常情况下和性能优化相对应
    • 两顶帽子:添加新功能和重构应该属于两种截然不同的行为,它们应该分开交替进行
  • 重构的好处
    • 改进软件设计,整理代码让后续的修改更容易
    • 让软件更好理解,准确说出我想要的
    • 帮忙找到bug
    • 提高未来的编程速度
  • 何时重构
    • 事不过三,第一次只管去做,第二次产生反感但还是去做,第三次做类似的事情就去重构
    • 修改bug时重构
    • review代码时重构
  • 间接层和重构:中间层能够允许逻辑共享和意图的分开解释,同时隔离变化和解耦。
    • 提前设计好中间层不如先直接做再重构
    • 少数情况下,中间层只会带来冗余
  • 重构的难题
    • 修改已有API:建议维护新旧两个接口,让用户做出反应后,再迁移。这期间,旧接口应该要调用新接口实现
    • 代码已经无法正常运行时,重写比重构更省事
  • 重构和性能优化:大多数的性能优化集中在小部分代码上。先写出风格良好的代码,再使用性能工具实测数据,对瓶颈处单独优化性能。好的重构也会让性能优化更容易进行

坏味道

在遇到下面一些“味道”时,可能你就需要重构了。

  • 重复代码
  • 函数过长,每当你需要用注释说明点什么时,可以把需要说明的东西写到一个独立函数中
  • 太长的类
  • 函数入参过多
  • 发散式变化:一个类因为多个原因发生不同的变化
  • 霰弹式变化:一个原因引起一个类的多个变化
  • 特性依恋:函数对某个类的兴趣高于自己所在的类
  • 数据泥团:喜欢聚合在一起的零散数据字段
  • 基础类型偏执:对于基础类型如字符串、整型不愿意使用简单类来封装
  • swtich语句
  • 冗余类
  • 夸夸其谈未来性:过度为未来设计
  • 令人迷惑的暂时字段
  • 过度耦合的链式调用,如a.b.c().d(),链上任意类做修改都会影响整个调用
  • 两个类的狎昵关系
  • 异曲同工的类
  • 幼稚的数据类:只有最简单的getter和setter
  • 子类拒绝继承超类的函数或数据
  • 过多的注释

测试体系:重构的保证

前面已经提到数次,重构的前提是不对已经已有行为做改动,这需要测试的帮助。本章对建立测试给了一些简单的介绍。

  • 编写测试代码最有用时机是编程之前
  • 编写一个测试case时,可以先让测试失败,再通过成功验证程序功能
  • 遇到bug时,先添加一个单元测试复现这个bug
  • 测试不能保证程序没有bug,编写测试样例也遵循82原则,当样例已经很多时,它带来的边际效果就没那么好了。应该更多考虑容易出错的边界条件,积极思考如何“破坏代码”。

重构列表

下面分几大方向介绍具体的重构手段。每个手段会分场景、思路、动机、做法来展开。

组织函数

日常工作中,非常容易坏味道中的过长函数,下面的一些重构方式可以帮我们优化这一点。

提炼函数

  • 场景:有一段相对独立的代码可以被组织并独立出来
  • 思路:将这段代码放到一个独立函数中,用函数名解释该函数的用途
  • 动机:有时会遇到过长函数中有一段需要注释才能看明白的代码。将这样相对独立的逻辑拆分成表意的短小函数后,可以让高层函数读起来就像一系列注释。如果提炼可以提高代码清晰度,就算函数名比函数体长都无所谓
  • 做法:用做什么而不是怎么做来为函数命名(如果你想不出一个更有意义的名称,就别动了)。检查是否有临时变量,如果有读取,可以作为入参传递给函数;如果对临时变量甚至有再赋值,那可能还要让函数返回临时变量修改后的值

内联函数

  • 场景:函数本体和名称一样清晰易懂
  • 思路:在函数调用点插入函数本体,然后移除函数
  • 动机:如果函数本体足够简单,且表意清晰,同时调用点有限,不具备多态性。那么出于减少无用中间层的考虑,可以直接使用函数体
  • 做法:注意检查是否有多态性

内联临时变量

  • 场景:一个临时变量只被简单表达式赋值一次,同时妨碍了其他重构手法
  • 思路:将对变量的引用动作,替换成给它赋值的表达式本身
  • 动机:过多的临时变量会妨碍你重构长函数
  • 做法:注意确保表达式没有副作用

以查询替代临时变量

  • 场景:程序中有个临时变量保存了某个表达式的运算结果,同时被多处引用
  • 思路:将表达式提炼成独立函数,在独立变量的所有引用点替换成对新函数的调用
  • 动机:替换成函数后,整个类都可以获得这份信息,同时会减少对该变量的频繁引用带来的重构困难
  • 做法:寻找只被赋值一次的临时变量,对于赋值多次的临时变量使用“分解临时变量”方法先重构,保证提炼出来的函数没有副作用。先不要担心性能问题,等到出现了优化也会比较简单

引入解释性变量

  • 场景:有个复杂的表达式,表意不够清晰
  • 思路:将表达式的值放进一个临时变量,用变量名表意
  • 动机:表达式不如变量名更好阅读。如果临时变量在整个类都有意义,建议直接使用“提炼函数”方法
  • 做法:先判断是否使用“提炼函数”的做法

分解临时变量

  • 场景:某个临时变量被多次赋值,且每次赋值意义不一样
  • 思路:针对每次不同意义的赋值使用不一样的临时变量
  • 动机:临时变量的多义性会增大理解成本
  • 做法:寻找被多次赋值且有多义性的变量,不同的意义使用新的不同临时变量

移除对函数入参的赋值

  • 场景:对函数入参赋值
  • 思路:用新的临时变量取代入参
  • 动机:对入参赋值会混淆按值传递和按引用传递的传参方式
  • 做法:略

用函数对象取代函数

  • 场景:大型函数中代码过于复杂,无法使用“提炼函数”
  • 思路:直接将函数放在单独对象中,将复杂的局部变量变成对象字段,从而可以轻松地在对象中分解这个大型函数到多个小型函数
  • 动机:略
  • 做法
    1. 建立一个新类,用函数用途给这类命名
    2. 在新类中创建final字段保存大型函数所在的对象,即“源对象”
    3. 新类的构造函数使用原函数入参作为入参
    4. 新类中建立computed()函数
    5. 赋值原代码到computed()中
    6. 在原函数位置,创建这个新类的一个对象,并调用这个对象的computed()函数
    7. 继续重构新类中的computed()函数

替换算法

  • 场景:某个算法有更清晰的算法替代
  • 思路:直接更换函数本体
  • 动机:略
  • 做法:略

对象间的特性搬移

类应该承担清晰且明确的责任。不论是承担责任过多还是“不怎么负责任”,都需要进行重构。

搬移函数

  • 场景:有函数和所在类以外的其他类反而有更多交流,如调用或被调用
  • 思路:在和函数交流更多的类中建立一个有类似行为的新函数,改造旧函数为新函数的委托函数,或者直接移除旧函数
  • 动机:略
  • 做法:
    • 检查和搬移函数关联的字段或函数,判断是否要一起搬移
    • 检查子类和超类有无其他声明,检查有无多态性
    • 如果目标函数需要太多源类特性,就需要进一步分解后再搬移

搬移字段

  • 场景:某个字段和所在类以外的其他类有更多交流
  • 思路:在目标类新建字段,修改源字段的所有使用者,令它们使用新字段
  • 动机:略
  • 做法:如果字段的访问级别是public,需要先用“封装字段”手段制造一个委托中间层

提炼类

  • 场景:某个类做了两个类的事情
  • 思路:建立新类,搬移函数和字段
  • 动机:一个类应该是清楚的抽象,即可以使用清晰的命名
  • 做法:拆分类,建立两个类之间的单向或双向连接,搬移底层函数,搬移高层函数

内联化类

  • 场景:某个类没做什么事情
  • 思路:将这个类的特性搬移到其他类,然后移除原类
  • 动机:通常会由于此前的重构动作移走了这个类的责任
  • 做法:选择和这个类关系最近的类进行合并,可以先在目标类中使用委托,然后再通过搬移函数的方式完成重构

隐藏委托关系

  • 场景:使用者通过委托类来调用对象
  • 思路:在提供服务的类上直接建立使用者所需的所有函数,隐藏委托关系
  • 动机:隐藏调用关系可以减少实现细节暴露从而减少耦合
  • 做法:在发起请求的类中,直接实现功能的接口,移除使用者的委托代码

移除中间人

  • 场景:类做了过多简单委托的动作
  • 思路:让使用者直接调用受托类
  • 动机:当“隐藏委托关系”使用过多时,封装会很痛苦,这个时候不如直接让使用者通过链式调用用中间受托类实现功能
  • 做法:刚好是“隐藏委托关系”的反向过程

引入外加函数

  • 场景:需要为提供服务的类新增函数,但是你无法修改这个类(通常是库代码)
  • 思路:在使用者类中建立一个函数,并用第一参数的方式传入服务类实例
  • 动机:尽管可以在不修改服务类代码的情况下,自行添加新函数,但还是建议当外加函数较多时,使用“引入本地扩展”的方式,或直接推动服务类升级
  • 做法:在客户类中建立函数,这个函数不调用客户类特性,只是转发请求到服务类

引入本地扩展

  • 场景:需要为服务类添加一些额外函数,但你无法修改这个类
  • 思路:建立一个新类,使其包含这些额外函数,让这个扩展类成为源类的子类或包装类
  • 动机:子类工作量较少,但是必须在对象创建期接管创建过程;包装类只是单纯转发请求,没有这个限制,但是转发过程都需要自己实现
  • 做法:略

重新组织数据

自封装字段

  • 场景:直接访问一个字段的方式给你的重构带来了麻烦,或是引入了麻烦的耦合关系
  • 思路:用取值/设值函数替代直接访问字段
  • 动机:这种方式让字段更为灵活,但是根据奥卡姆剃刀法则,等需要的时候再用
  • 做法:有的字段可能需要一个初始化函数

用对象取代数据值

  • 场景:数据项需要和行为合在一起使用才有价值
  • 思路:把简单的数据项封装成对象
  • 动机:开发初期的简单数据,可能在迭代后会加上特殊行为,如果不及时处理,就会出现特性依恋或重复代码
  • 做法:略

将值对象改为引用对象

  • 场景:从一个类会衍生出多个实例,实例间只是一个实体的多种状态
  • 思路:将值对象改为引用对象
  • 动机:值对象通过equals()或hashCode()判断,如日期;引用对象则直接可以用相等操作符==判断,如顾客、账户等概念
  • 做法:你可能需要一个静态字段或提前创建好多个新对象作为访问点

将引用对象改为值对象

  • 场景:你的引用对象很小且不可变,同时不易管理
  • 思路:将引用对象改为值对象
  • 动机:引用对象不好控制,值对象的不可变特性在某些场景很好用。
  • 做法:只有不可变对象才能被重构

以对象取代数组

  • 场景:有个数组,其中的元素类型不一,代表不同的东西
  • 思路:用对象替代数组,用字段表示不同意义的元素
  • 动机:数组的作用是以某种顺序存储一组相似对象,不要让位置具有特殊意义
  • 做法:略

复制被监视数据

  • 场景:有些领域数据被放在了GUI部分代码里
  • 思路:将数据复制到领域对象中,建立Observer模式,剥离UI和逻辑
  • 动机:分层良好的系统,用户界面和业务逻辑代码是分开的,这样也更好维护
  • 做法:略

将单向关联改成双向关联

  • 场景:两个类都需要对方特性,但目前只有单向连接
  • 思路:增加一个反向指针,同时修改函数能够同时更新两条链接
  • 动机:略
  • 做法:注意删除过程移除指针的顺序

将双向关联改为单向关联

  • 场景:两个类有双向关联,但是一个类已经不需要另一个类的特性
  • 思路:去除不必要连接
  • 动机:维护双向连接带来便利的同时,也会增加维护的复杂度
  • 做法:略

用常量取代魔法数

  • 场景:有个字面量数值,具有特殊含义,但是不能一眼看明白
  • 思路:创造一个常量,用命名说明字面数值的意义
  • 动机:魔法数是类型码时,要使用“以类取代类型码”
  • 做法:略

封装字段

  • 场景:类中有public字段
  • 思路:声明改为private,提供相应的访问函数
  • 动机:暴露public会降低函数的模块化程度,数据应该和行为集中在一起,不应被直接修改
  • 做法:略

封装集合

  • 场景:函数返回一个集合
  • 思路:返回集合的只读副本,并在类中提供添加/移除集合元素的函数
  • 动机:类似“封装字段”,返回的集合一样可能被修改
  • 做法:使用Collection,或返回一个副本

用数据类取代记录

  • 场景:面对传统编程中的记录结构
  • 思路:创建“哑”数据对象
  • 动机:要将记录型结构转成面向对象的程序中
  • 做法:创建private字段,创建读写函数并提供

以类取代类型码

  • 场景:类中有个数值类型码,但是不影响类行为
  • 思路:用新的类替换数值类型码
  • 动机:略
  • 做法:略

以子类取代类型码

  • 场景:类中有个不可变数值类型码,同时影响类行为
  • 思路:用宿主的子类替换类型码
  • 动机:可以用子类的多态性取代switch语句,不过,如果类型码会发生改变,或者宿主类已经有子类则不能用此方法
  • 做法:略

以状态/策略取代类型码

  • 场景:类中有个数值类型码,会影响类行为,同时不能通过继承来消除
  • 思路:以状态对象取代替换数值类型码
  • 动机:略
  • 做法:创建一个新的类,用类型码的用途为它命名,这就是一个状态对象。所有的新类继承自超类,返回不同的状态码

以字段取代字段

  • 场景:子类的查边只在返回常量数据的函数上
  • 思路:修改函数,让它们返回超类的新增字段,然后销毁子类
  • 动机:这样可以避免继承带来的额外复杂性
  • 做法:略

简化条件表达式

条件逻辑会增加理解的层级,处理不好时,很容易配合长代码造成理解困难。

分解条件表达式

  • 场景:有一个复杂的条件语句
  • 思路:为if、then、else语句段落提炼独立函数
  • 动机:条件逻辑通常会使代码更难阅读
  • 做法:使用表意的函数名说明条件语句意思

合并条件表达式

  • 场景:有一系列的条件逻辑,都得到相同结果
  • 思路:合并成一个条件表达式,并将之提炼成一个独立函数
  • 动机:有时候这么做能把“做什么”的语句转换成“为什么”的含义,前提是这些检查并非彼此独立
  • 做法:注意确认条件语句都没有副作用,有些条件表达式甚至可以简化成三元表达式

合并重复的条件片段

  • 场景:条件表达式的每个分支都有相同的一段代码
  • 思路:将代码提取到条件表达式之外
  • 动机:减少重复语句
  • 做法:略

移除控制标记

  • 场景:在一系列布尔表达式中,某变量具有控制标记的作用
  • 思路:用break或return替代
  • 动机:有时候为了可读性和可维护性,可以牺牲单一出口的做法
  • 做法:略

用“卫语句”替代嵌套条件表达式

  • 场景:嵌套的条件逻辑过多,难以看清正常执行路径
  • 思路:用“卫语句”枚举出所有特殊情况,减少嵌套层数
  • 动机:当特殊case多于正常case时,提前处理每种特殊情况,可以有效减少嵌套层数
  • 做法:注意“卫语句”要么就从函数返回,要么就抛出异常,反正要跳出当前执行流

用多态取代条件表达式

  • 场景:你手上有个条件表达式,根据对象类型不同选择不同行为
  • 思路:将条件表达式的每个分支放在子类的重载函数中,然后将父类的原始函数声明为抽象函数
  • 动机:面向对象程序中,更少出现switch语句也是得益于多态这个工具
  • 做法:略

引入Null对象

  • 场景:在很多地方检查对象是否为null
  • 思路:用一个特殊的Null对象取代null值
  • 动机:空对象对外就像是特殊的空的对象(Go笑而不语),而不是什么都没有,有利于保证函数行为的一致性
  • 做法:空对象一定是单例的

引入断言

  • 场景:某段代码需要对程序状态做出假设
  • 思路:用断言表示这种假设
  • 动机:有些时候,只有某个条件为真,代码才能正常运行,这个时候用断言明确这些假设。
  • 做法:注意不要滥用断言,只用来检查“一定为真”的条件,而不要去检查“应该为真”的条件

优化函数调用

我们在前面提到了函数体本身的优化,这一章我们主要介绍函数调用的优化

函数改名

  • 场景:函数名没能说明函数用途
  • 思路:修改函数名
  • 动机:优化函数名,让它达到注释的效果,重新安排参数顺序,提高代码清晰度
  • 做法:对于旧函数,可以标注deprecated,说明其不建议使用

添加参数

  • 场景:函数需要从调用端得到更多信息
  • 思路:为函数添加新的对象参数
  • 动机:如果有其他重构的方法,只要可能,基本都比添加参数要好
  • 做法:略

移除参数

  • 场景:函数本体不需要某个参数
  • 思路:去除该参数
  • 动机:暂时不要考虑未来是否能用到
  • 做法:略

分离查询和修改

  • 场景:一个函数即返回对象状态,同时又有副作用
  • 思路:将查询和修改分离出两个参数
  • 动机:任何有返回值的函数,最好都不要有看得见的副作用
  • 做法:先分离查询,再分离修改

让函数携带参数

  • 场景:若干函数做了类似的操作,仅仅因为某些值表现不同
  • 思路:用一个单一函数表示,用参数来表示那些不同的值
  • 动机:减少重复代码
  • 做法:略

用明确函数取代参数

  • 场景:有一个函数,其中完全取决于参数表现出不同行为
  • 思路:针对参数的不同值,建立一个独立函数
  • 动机:函数内大多以条件表达式检查这些参数值,并作出不同行为;有时也可以用多态实现
  • 做法:略

保持对象完整

  • 场景:你从对象中取了若干字段,将它们作为函数调用的一些参数
  • 思路:改为传递整个对象
  • 动机:如果传递整个对象会让你的依赖结构恶化,那么就不该用这个方法
  • 做法:略

用函数取代参数

  • 场景:对象调用某个函数,用其结果做参数传递给另一个函数,然而接受改参数的函数本身也能调用到前一个函数
  • 思路:让参数接受函数直接去调用前一个函数,然后去除该参数
  • 动机:如果函数有其他途径获得参数值,就不该通过参数获得
  • 做法:略

引入参数对象

  • 场景:某些函数入参总是在一起出现
  • 思路:直接用一个对象取代这些参数
  • 动机:略
  • 做法:略

移除设值函数

  • 场景:类的某个字段在创建时设值,然后就不再改变
  • 思路:去掉字段的设值函数
  • 动机:提供设值字段就表示可能被改变
  • 做法:略

隐藏函数

  • 场景:有函数从未被其他类用到
  • 思路:将函数改为private
  • 动机:减少无谓的API暴露
  • 做法:可以利用lint工具帮忙检查

用工厂函数替代构造函数

  • 场景:希望创建对象时不仅做简单的构建动作
  • 思路:使用工厂函数
  • 动机:这个方法也可以用来通过类型码创建类对象
  • 做法:结合Class.forName()可以不用写switch语句

封装向下转型

  • 场景:函数返回的对象需要由调用者向下转型
  • 思路:将向下转型放在函数中进行
  • 动机:略
  • 做法:略

用异常取代错误码

  • 场景:函数返回特性的代码表示错误情况
  • 思路:改用异常
  • 动机:异常能够区分出正常情况和异常处理
  • 做法:需要决定抛出受控异常或者非受控异常

用测试取代异常

  • 场景:对于一个调用者可以预先检查的条件,抛出了异常
  • 思路:修改调用者,改在调用前进行检查
  • 动机:能够提前检查的情况,就不算是异常
  • 做法:略

处理继承关系

字段上移

  • 场景:两个子类有相同字段
  • 思路:将字段移至超类
  • 动机:归纳重复特性
  • 做法:略

函数上移

  • 场景:两个子类有相同作用的函数
  • 思路:将函数移至超类
  • 动机:归纳重复特性。子类的函数覆写超类函数,但是做相同工作时,也要使用函数上移
  • 做法:略

构造函数上移

  • 场景:子类的构造函数几乎完全一致
  • 思路:在超类中新建构造函数,再在子类构造函数中调用它
  • 动机:如果重构过程过于复杂,可以考虑使用“用工厂函数替代构造函数”
  • 做法:略

函数下移

  • 场景:超类的某函数只和部分子类有关
  • 思路:将函数移到相关的子类中去
  • 动机:和“函数上移”恰恰相反
  • 做法:略

字段下移

  • 场景:超类的字段只被部分子类用到
  • 思路:将字段移到真正需要的子类中去
  • 动机:和“字段上移”恰恰相反
  • 做法:略

提炼子类

  • 场景:类的特性只被部分实例对象用到
  • 思路:新建一个子类,将未被用到的特性转移到子类中
  • 动机:上述的差异行为有时也可能通过类型码区分,这个时候可以由“以子类取代类型码”或“以状态/策略取代类型码”方法来重构
  • 做法:略

提炼超类

  • 场景:两个类有相似特性
  • 思路:为两个类建立超类,将相似特性移到超类中
  • 动机:两个类用相同方式做类似事情往往意味着重复代码
  • 做法:略

提炼接口

  • 场景:若干客户端使用类中的同一子集,或者两个类有部分相同点
  • 思路:将相同的子集提炼到独立接口中
  • 动机:接口有助于系统的责任划分和能力声明(鸭子类型)。在单继承的语言中,接口扮演了组合功能代码的角色。尤其某个类在不同环境表现不同时,使用接口是个好主意
  • 做法:接口命名通常由-able结尾

折叠继承关系

  • 场景:超类和子类几乎无法区分
  • 思路:将它们合为一体
  • 动机:往往在过度设计时出现
  • 做法:略

构造模板函数

  • 场景:有一些子类,细节上有所区别,但是整个流程上操作类似
  • 思路:提炼出操作流程,上移至超类,将具体细节操作放在独立函数中,让它们有相同的签名,然后实现超类的抽象函数
  • 动机:这样抽离出来的流程函数也叫模板函数,模板上插槽接口固定,然而提供插槽的模板函数是一致的
  • 做法:后续新增的类,只需实现超类抽象函数就可以完成扩展

用委托取代继承

  • 场景:子类只使用超类接口的一部分,或者直接不需要继承来的数据
  • 思路:在子类中新建字段保存超类,然后调整子类函数,让它委托超类,然后去掉两者的继承关系
  • 动机:略
  • 做法:略

用继承取代委托

  • 场景:两个类的委托关系过多,且委托函数都很简单
  • 思路:让委托类继承受托类
  • 动机:如果你没有使用所有受托类函数,那么就不要用这个重构方法,继续保持委托关系,使用其他重构方法;另外受托对象可变时,也要注意
  • 做法:略

大型重构

Kent Beck和作者所写

本章介绍了4个大型重构的思路,也是大型程序容易遇到的4个问题

  • 梳理和分析继承体系:往往因为某个继承体系承担的两个甚至更多责任,有一个特征是,某一层级的所有类,子类都以相同形容词开始。可以通过委托的形式,对继承体系做正交化
  • 过程化设计转化为对象设计:往往出现在过程化风格传统语言中。可以将数据记录变为对象,拆分大块行为为小块,然后将行为转移到相关对象中。
  • 分离领域和UI:出现在有GUI的场景中。传统的MVC设计模式就是将领域逻辑分离出来,用接口的方式和UI部分代码对接
  • 提炼继承体系:有的类做了太多工作,里面经常有较多的条件表达式。对于这种,可以借助面向对象中的子类和多态或者策略模式实现

重构与现实

重构在某些角度和技术演进很像。技术的接纳过程类似一条钟形曲线。前段包括先行者和早期接受者,中部大量人群包括早期消费者和晚期消费者,最后则是行动迟缓者。不同人有不同的消费动机。先行者和早期接受者感兴趣的是新技术,“范式转移和突破性思想”的愿景;早期和晚期消费者则关心成熟度、成本、支持程度,以及这种新思想/新产品是否被和他们相似的其他人成功使用。

尾声

  • 重构工具能节省你的重构时间
  • 永远记住“两顶帽子”,重构时保持代码功能不变

《软技能 —— 代码外的生存指南》书摘

发表于 2020-08-12 | 分类于 思考 |

关于编程相关的书籍已有太多太多,本书相比其他编码相关的技术书籍来说,从技术外的视角来介绍还是挺有意思的。编码无非是求生的一种方式,对于程序员来讲,把生活过好也绝不仅是把代码写好就OK的。书中所写基本是作者对其过去职业和人生经历的一个总结,以tips的形式给出,是“术”而非“道”。是的,本书的介绍思路大概是告诉你一些方法,对你的生活和工作有些帮助的方法,而非构建一个体系,一种思考方式。因此,对于那些三观和做事方法思路基本稳定的人来说,它没法撼动你根本的认识,只能做到具体某个方面的启示和改进。同时,读起来也是相对简单的。不客气地说,这本书应该是最近一年中读到的信息密度最低的书了。不过,其中理财和健身两章,尤其是第55章应该算是全书的精华,对我还是挺有帮助的。

下面分章节,对其中的关键的idea进行摘录。

职业

可能由于作者大多数时间是自由职业者,这一部分介绍没有太多新意

  • 工作是公司的,职业生涯是你自己的
  • 把自己当成公司去思考,你有什么可以卖,相比其他“产品”你的优势是什么
  • 作为程序员,你能提供的基础服务就是创建软件
  • 人际交往不能忽略
  • 通过面试最快捷的方式是让面试官对你产生好感,如果能提前接触就更好了(Really?)
  • 承担更多责任是脱颖而出的一种方式,同时保证自己被注意到
  • 成为自由职业者之后,一定不要忘了自我营销

自我营销

作为自由职业者,作者在自我营销上有些自己的见解

  • 自我营销:打造自我品牌 + 多种媒介 + 持之以恒
  • 一个品牌需要包含:传达的信息(slogan) + 视觉符号(logo) + 一致性 + 曝光率,重点在建立一套预期
  • 不要忘了有效利用社交媒体,为自己积累粉丝
  • 学会演讲
  • 著书有时候不是为了赚钱,而是赢得名声

学习

  • 学习知识最好能将知识用于实践
  • 十步学习法:了解全局、确定范围、定义目标、寻找资源、创建计划、筛选资源、开始学习、动手操作、全面掌握、乐为人师
    • 前6步能让你明确方向和目标,为正式学习做准备
    • 后面4步循环往复,快速迭代,乐为人师能强行提高你的理解程度
  • 有时候导师也很重要
  • 遇到知识短板时,就是你成长的机会

注意力

  • 专注像是一种惯性,是逐渐达到的,不可能一次性达成
  • 番茄工作法:将时间拆分成30分钟的番茄钟(25分钟专心工作 +5分钟休息),通过番茄钟衡量工作量和自己的工作效率(实际工作中太容易被打乱节奏了,比较适合自由职业者)
  • 定额工作法:对于需要定期完成的任务,自我规定周期内需要达到的工作量,承诺然后完成。有时候可以借助大众的监督来坚持
  • 多任务并行通常会因为上下文切换影响工作效率,除非另一项任务不需要花费脑力
  • 电视是时间杀手
  • 为了享受快乐有意识地去做,就不是浪费时间;为了逃避自己应该完成的任务去做,就是浪费时间
  • 分解任务可以有效地减小解决问题的困难程度
  • 任何行动都比不行动要好(主要是行动可以获得反馈)

理财

本篇是全书相对最有信息量的一篇。其中第55章对于自己生涯的描述,甚至比其他所有篇章的介绍都要精华。其他章节可能有粉饰自己的成分,但是第55章“额外馈赠”足够真诚。

  • 资产是使用价值高于维护成本的东西,负债则相反。减少负债,增加资产
  • 自我营销越好,薪酬越好谈
  • 期权是指在未来某个时期前购买一定数量股票的选择权,购买的是期望。买方最大亏损有限,最大盈利无限,有权利没有义务;卖方相反。看涨期权和看跌期权作为买方都需要交期望差额的权利金。到期日时(这是欧式期权的做法,美式期权可以在到期日前任意时间交易),买方可以选择或放弃行权,选择行权时,买方卖出股票,赚取高于权利金的差额;放弃行权时同时放弃权利金。
  • 房地产投资是低风险高负债的投资类型,一方面可以寻求房产出售的机会,另一方面可以通过租金获取稳定收入。当然在租赁房产时,建议选择负责任的物业托管。通过部分租金换取安心。
  • 想要提前退休,需要有资本积累,同时,这个资本还要让你获得足够生活的被动收入。如果有提前退休打算,需要下面几点准备
    • 树立目标,即XX岁前退休
    • 意识到通胀的存在,他会吞噬你赶不上它速度的资产
    • 做有固定收益和被动收入的投资(最好还能赶上通胀)
    • 要想更早退休,自然要比常人花更多精力“开源”和“节流”
  • 真正获得财务成功的唯一方法就是用钱生钱
  • 一边欠债一边存钱是最愚蠢的做法,因为债务利息永远高于存款利息。
    • 存钱之前先把房屋抵押贷款还清(这么做还是有些绝对,还要留些以备急用)
    • 能一次付清就一次付清,除非你能通过提前享受获得超过利息的收益
    • 确保先偿还利息最高的债务
    • 并非所有债务都是不好的,除非你能通过提前享受获得超过利息的收益(如住房贷款和学生贷款)
  • 退休即自由,即可以不以钱作为出发点行事,更形象地说,“从社会中赎回自己的生活”。
  • 买房办理贷款时注意贷款利率是否是固定的
  • 作者最初也是程序员的工作,之后逐渐贷款购置房产用于租赁,通过日常工作还款。之后几次创业都不太成功。但是房产累积越来越多。之后通过个人营销开始创办博客和培训教程,认识大佬后,培训教程逐渐受到欢迎。之后订下退休目标,随着房产带来的被动收入和在线培训(编程 + 健身 + 创业)被动收入逐渐稳定,作者成功上岸退休

健身

  • 同时达到多个健身目标是很难实现的。很难在增肌同时减掉脂肪,同样地,很难在减脂同时增长肌肉
  • 减肥很简单:摄入的卡路里小于燃烧的卡路里。
    • 摄入卡路里通过食物计算,但是烹饪过程对热量也有很大影响
    • 燃烧的卡路里可以根据基础代谢率BMR结合训练消耗计算
  • 增肌需要给肌肉压力,挑选动作的时候注意选择复合动作,如深蹲、硬拉、卧推、杠铃推举等等。注意保持足够的蛋白质摄入
  • 腹肌不是靠增肌得到,而要通过减脂。体脂率下降到特定水平自然能看到腹肌。可以通过高强度间歇式训练(HITT)来减脂
  • 跑步和站立式办公都是简单的燃脂方式

心灵

  • 积极思考不只是外表乐观,而且对健康有益,延年益寿
  • 做事方法的第一步是相信自己有改变的能力,改变不了现状,你至少能改变自己的心态。
  • 爱情不是追逐游戏,你追我逃。更健康的模式是行为上体现出自信,用自然随和且充满自信的态度和别人交往。“我自己感觉很好,我不需要你,但是我觉得你挺有意思的,所以我想更好地了解你”
    • 关键是你要真得能表现出足够的自信,你要对自己足够尊重
    • 做一个绝望的、缺乏自信的人,你会发现自己会真的孤立无援
  • 那些拒绝最终都会把你带到一个想和你在一起的人那里

结束语 & 附录

  • 生活原本比你所厌恶的朝九晚五的工作丰富多彩得多
  • 空头是指,你事先“借”该股票的一些股份并卖出,这会产生空头头寸,最终你需要靠回购这只股票来填补你借入的空头头寸
  • Ⅰ型糖尿病是指自身不能产生胰岛素,Ⅱ型糖尿病是指自身对胰岛素不够敏感
  • 吃垃圾食品不会对健康造成重大影响,但是摄入食品的总量却会影响健康。相比健康食品,垃圾食品带来更高热量的同时,只有较低的饱腹感。因此,达到标准热量所使用的垃圾食品可能会让你长期处于挨饿状态。
  • 水果和蔬菜都是健康食品,热量都不高;高蛋白食物的热量值通常也不怎么高。纤维带来饱腹感的同时有较低的热量
    • 总结来说,未经加工的食品就是最健康的

–END–

师兄师姐分享会

发表于 2020-08-04 | 分类于 思考 |

前一阵被邀请参与公司新任培训的师兄师姐分享环节,大体是和小组内的新入职校招同学分享工作中的积累和收获。分享内容没有要求,但是大家提的比较多的问题是入职后有没有什么成长的tips或者坑。我干脆提前做了些相关的准备,也一并在这里记录下来吧。

我回忆了下过去2年多以来,在公司遇到的之前未曾预期的种种,大致可以总结为下面两点:

  • 了解业务
  • 以人为本

先说了解业务吧。我们在日常工作中遇到的需求无非两类:业务需求和技术需求。这两类工作都要求对业务的了解。在业务需求中,首先了解业务才有可能完好地还原prd的需求,避免产生不符合预期的情况,避免被产品或QA打回。然后,我们每个人都不是需求实现的机器,了解业务能让你知道,你写的每一行代码都是有意义的,都是真真正正为人服务的,而不是机械地完成任务。同时,对业务的熟悉程度也能让你的视野上个台阶,从更高的角度考虑问题,看到更远的可能。实际上,服务端同学相对来说,由于要设计数据库表,实现底层的业务逻辑,需要对整个业务理解更深入,所以在大多数团队,leader也都是服务端同学担当。

在技术需求中,同样离不开对业务的理解。可能有些刚入职的同学不会意识到:我们其实是工程师,而不是科学家。我们需要把技术应用到实际工作中,而不是单纯地指出某个技术的可行性。失去业务土壤的技术需求是无法带来真正价值的。业务需要需要能够从业务中挖掘,并在最后真正应用到业务中产生价值。举个反例,在我刚入职时实现过一个流程图工具,想法很单纯,用技术实现工具是个很酷的事。然而没有考虑过如何应用到业务中,最后半途而废。类似地,在入职1年多的时候,和同事开发了能够托管UI稿和prd稿的平台,但是我们无视了市面上已经有太多成熟好用的产品,最终也没能推动业务使用。一个比较好的技术需求应该怎么做呢:了解业务需要、使用技术赋能,然后保证实现落地。这三步中,使用技术赋能反而是最简单的一步。理解业务需要和推动业务使用是比想象中要困难的。

第二点叫做以人为本。这也是刚加入工作时可能注意不到的一点,入职前你可能以为你每天很浪漫地和代码泡在一起,和机器打交道。真正工作一段时间后,你会发现,每天至少50%的时间是在和人打交道的。人和机器是不一样的,机器是可靠的,可预期的,可以根据在学校里学习的知识推测的;而人是不可靠的,需要技巧,需要将心比心。这种不一样的思维方式会给可能过于理性的你带来麻烦。不然你会发现每天70%~80%的烦恼都是人而非机器带来的。

说几个例子,展开聊一下。先说代码,代码是写给人看,写给人理解的,然后才是交给机器去执行。看似你是在写代码,实际上你是通过代码在和未来的你或者接手你代码的人交流思路。所以代码的风格、可读性可能比你想象中要重要。一个糟糕的代码风格、可读性会让未来的你或者其他同事想要骂人,想要通过git blame找到这一坨shi一样的代码究竟是哪一个如此没品味的人写出来的。相反,一个好的风格、可读性会让未来的你和你的同事接手代码时心情愉悦,如清风拂面。类似地,可扩展性和设计良好与否也能起到上面的效果。可扩展性强和设计良好的代码可以极高地提高修改代码的愉悦程度和生产效率。

作为前端,界面的设计也一样重要。不要只是单纯地去实现PM或者UI的设计,可以站在终端用户的角度换位思考。如果是你遇到这种交互,它是否符合你的直觉,使用起来是否够简单,是否能达到目的。遇到有疑问的地方,随时可以找PM和UI讨论。

当然,这里说以人为本也不要矫枉过正。各位在日常工作中,还是以做事为主,公司内也还是看大家工作成果如何,而不是人际关系搞的如何。这里只是提个醒,希望大家在踏实努力的同时,也不要忘记了“人”这个角色的重要性。

总结上来看,就是上面这些,没别的了。各位既然来参加今天的培训,肯定也是从学校的环境刚进入工作环境没多久。上面这段分享听完之后,如果能对有些人有启示,能让大家意识到思维方式的不同,就达到我的目的了。

谢谢!

12…26
shenlvmeng

shenlvmeng

Be sharp, my friend.

129 日志
10 分类
384 标签
RSS
GitHub Weibo
© 2014 - 2021 shenlvmeng
由 Hexo 强力驱动
主题 - NexT.Muse