对于很多从一线成长到管理岗位的员工来讲,管理工作和管理能力的阶段多少要靠自己领悟。可能从日常工作、文档培训中形成了管理工作懵懂认识,不成熟的归纳认知很可能会让你卡在某个阶段无法提升,又找不到办法。《领导梯队》这本书从基层开始分析管理路线上每一个阶段的做事思路,或许不能适应在所有场景下,但最起码能给人一种启示——什么才叫管理,以及想走管理路线的话,可以做些什么。当然,做事过犹不及,作为技术人员,理清管理思路后,别忘了你的本职工作。至少在前几个阶段,对你的技术能力是有要求的。

序和导论

在讨论领导梯队和领导力模型之前,我们要认清下面一些现状:

  • 在快速发展的行业里(如互联网),是缺乏领导人才的
  • 一味地引入,忽视内部培养,无法建立完善而持久的领导梯队

因此,公司需要一个领导力发展模型,模型从个人贡献者到CEO可以分为6个阶段:

  • 个人贡献者到一线经理
  • 一线经理到部门总监
  • 部门总监到事业部副总经理
  • 事业部副总经理到事业部总经理
  • 事业部总经理到集团高管
  • 集团高管到CEO

角色负责的范围逐渐扩大,在工作技能时间管理工作理念三方面的要求也各有侧重。

最后,书中提到的领导力模型和阶段并非适用于所有场景,需要根据实际情况灵活调整。毕竟人是复杂的,管理也是。

概述

这里具体介绍了领导力发展的6个阶段:

  • 从管理自我到管理他人
    • 从专业化、职业化思路转变到通过他人完成任务作为自己取得成功的关键
  • 从管理他人到管理经理人员
    • 负责选拔人才成为一线经理
    • 帮助一线经理清除“依靠自己获得成功”的错误观念
  • 从管理经理人员到管理职能部门
    • 战略眼光
    • 跨层级沟通
    • 和其他部门合作,基于工作需要帮自己部门争取资源
  • 从管理职能部门到事业部总经理
    • 清楚管理工作和市场结果的关系
    • 从盈利和长远发展出发
    • 兼顾长远和近期目标
    • 更多时间用来分析反思
  • 从事业部总经理到集团高管
    • 资金调拨和人才配置
    • 培养事业部经理
    • 评估业务投资组合策略
  • 从集团高管到CEO
    • 从管理技能转变到经营理念
    • 远大抱负、权衡取舍、外部视角

在小公司里,可能不会有这么多领导力的层级。

管理自我到管理他人

关键词:团队努力、计划、沟通

随着个人贡献者能力的提升,一部分人会被提拔到职业生涯里第一个领导岗位上。在这个岗位上获得成功需要心态上的一大转变,即工作成功不再通过自己亲自做获得,而是通过下述和团队的努力获得。在这个位置,经理身上需要承担一些管理动作,包括:

  • 制定计划
  • 工作涉及
  • 人员选拔
  • 授权
  • 绩效监督、评估
  • 辅导和反馈收集
  • 沟通和氛围营造
  • 获取资源
  • 奖励和激励

在时间管理上,需要划分出更多时间做:

  • 执行计划
  • 和下属沟通
  • 和兄弟部门、客户、供应商等沟通

这一阶段可以采用下面一些手段帮助经理对齐领导力模型:

  • 准备:提前对齐岗位期望
  • 监督:通过旁听、360评估、和同行比较等方法
  • 干预:oneone沟通,引导

一线经理是未来领导者的摇篮,在选拔这类人才时,可以考察此人帮助别人成功的意愿以及是否可以从帮助别人获得满足。

管理他人到管理经理

关键词:授权、选培一线经理、部门协作

这个过程通常代表着从一线经理到部门总监。工作上也主要围绕着一线经理展开,主要职责是整合工作、分配资源和培训管理者。要敢于授权,同时建设授权后的问责系统,另外开始培养战略和文化的问题。作为一个部门总监,至少需要以下几个技能:

  • 选拔和培养有能力的一线经理
    • 建设性批评、就事论事
  • 让一线经理对管理工作负责
    • 对齐期望,减少越俎代庖
    • 调整不合适的一线经理
  • 在部门配置资源
    • 根据部门情况调配资源(薪水、项目等)
  • 协调下属部门和其他部门的管辖
    • 信息共享,鼓励团结协作
    • context、not control

其中第一项能力最为重要,要善于授权,培养大局观。寻找对管理工作有真正热情的人。在交流时,把一线经理当成一个团队而非一线员工。部门总监是第一个完全依靠管理技能而非从事专业技术工作的管理层级,要能够传递高层战略到基层员工,也要能将基层员工的执行能力反馈给战略制定者。

管理经理到管理职能部门

关键词:信息收集、全局观、战略思维、成熟度

职能主管这个层级会有多种信息来源,需要能够熟练地收集和理解信息,沟通上从交谈转为倾听,要能积极倾听开放思想。另外,职能主管需要认识到,他不再是职能部门的一员,而是该部门的领导者。他需要拥有战略性思维,可以胸怀全局把握整体,而不是依赖以往领域的经验做事:

  • 长期思维(3-5年)
  • 关注业界最新发展动态
    • 技术方面
    • 经营方面
  • 全面了解商业模式和战略目标
    • 业务目标
    • 市场定位
    • 战略变动
    • 如何盈利
    • 团队优势
    • 所在部门可以做出的贡献
    • 其他部门的贡献
  • 将职能部门的所有方面纳入战略考虑,这也要求了解之前不甚熟悉的其他职能领域

一个称职的事业部副总应该是成熟的。这体现在:

  • 谦逊好学、坦诚清晰
  • 善于授权、相信他人
  • 乐于沟通,善于表达
  • 和兄弟职能部门保持合作而不是竞争,因为个人成功和进步只有在企业成功时才有可能实现

与之相反,可能会出现下面这些bad case:

  • 无法从项目运作导向转变到战略导向
  • 不重视不熟悉或是不感兴趣的工作
  • 表现不成熟

管理职能部门到事业部总经理

关键词:时间管理、工作透明、部门权衡、视野开阔

相对职能主管,事业部总经理工作的曝光度要高得多,他有很强的掌控权,也对成本和收入直接负责。副总经理需要制定业务战略和整合各部门工作。对比职能主管的部门策略思维,事业部总经理的业务战略思维要求他拥有更广泛的视野,综合无数外部因素,考虑本行业甚至全球事务。

  • 如何实现业务增长
  • 如何提高盈利水平
  • 如何增强竞争优势

这个思维模式的转变是有难度的,也是必须完成的。

事业部总经理需要处理错综复杂的各种问题,兼顾短期和长期目标。为了了解业务的方方面面,保证视野开阔,他还需要时间学习很多新知识。时间管理成为一个难题。事业部总经理不能单单依靠个人能力获得成功,他需要把部门经理整合成高效团队,重视和平衡所有部门,并把具体工作授权给它们。事业部总经理的关注对比副总经理更为强烈,在项目、计划和人员管理上也有很大权限,这也让他的一举一动十分透明。做每一个决定前都要认真考虑。

自我提升上,可以借助协同三角形模型:

  • 战略方向
    • 竞争优势:产品、市场、客户
  • 人员能力
    • 经验
    • 技能
    • 思维模式
    • 视角
  • 组织能力
    • 组织结构
    • 工作设计
    • 工作流程
    • 权力配置
    • 人员配置
    • 组织文化

可以通过考虑一些问题来实现上面的思考方式:

  • 我们有合适的产品么
  • 我们的竞争优势能报纸么
  • 我们的客户细分市场何合适么
  • 员工是否有创新意识
  • 我们是否有客户导向的思维模式
  • 我们的产品研发部门是否有足够授权
  • 我们的各部门是否可以有效组织

事业部总经理到集团高管

关键词:集团战略、新机会、选培事业部总经理

晋升到集团高管后,脱离了具体某项业务。要学会从集团的角度出发制定战略,辅导培训事业部总经理。具体体现在

  • 和事业部领导班子保持交流,选拔和培养总经理
  • 评估各事业部的战略规划,批准它们的业务规划而不是亲自管理
  • 超越财务结果评价事业部总经理
  • 监督各业务部门奉行公司的价值观和各项政策
  • 在必要的时候使用兼并收购的方式补充业务

集团高管还要能抽出时间发现行业里的潜在机会和新商机。

一个合格的集团高管需要有下面的标准:

  • 业绩优异
  • 出色的战略能力
  • 有效的人才培养
  • 对客户满意充满激情
  • 敏锐的商业头脑
  • 愿意共享资源
  • 践行公司价值观
  • 关心公司成功

从集团高管到首席执行官

关键词:可持续发展、执行力、组织能力培养、长期思想

首席执行官受到各方的密切关注,不容出错。在领导力模型里面临下面一些挑战:

  • 平衡长短期利益,实现可持续发展
  • 设定公司发展的方向,承担风险,深思熟虑
    • 公司方向、行业变化、商业模式、竞争格局
  • 培养组织能力,保证人才供给
  • 确保战略执行到位,对如何盈利有与生俱来的直觉
    • 我的表现如何
    • 我了解公司的情况么
    • 有向上反馈渠道么
    • 董事会履行自己授权么
    • 我的团队高效有活力么
  • 处理好全球化和外部关系

培养首席执行官没有捷径,一个首席执行官需要经历领导力模型的大多数阶段,他的理想路径包括:

  • 在核心业务部门的多个职位工作过
  • 有海外任职经历
  • 领导业务部门实现突破性增长
  • 领导新兴业务和振兴衰落业务
  • 主管过公司的人力资源

首席执行官的工作目标通常都需要较长的时间才能逐步达成,工作理念上也要有所转变。

诊断问题

在上面介绍完了整个领导力模型后,这里可以比照着整个模型,定期做整个组织的审视,很容易发现人员错误配置在某一层级的情况。通常因为在快速晋升的过程中,遗漏或仓促跳过了一些发展阶段,做事思路还没有转变。这会引起:

  • 虽然短期业务看着不错,对长期可持续发展却没有帮助
  • 越俎代庖和工作效率下降
  • 对员工职业发展不利

在评估时,可以通过和个体以及个体的上下级沟通,判断在领导技能、时间管理、工作理念几方面是否和层级相匹配。

改善业绩评估

在日常的绩效评估中,可以加入领导模型的能力评估。避免出现职责断裂或者重叠的情况。可以用圆圈标识一个员工的7项绩效内容期望。当达到全面绩效时,可以考虑将他人名到一个新的领导岗位。每提升到一个新的领导层级,从会出现绩效缺口。在培训工作持续进行时后,培训对象会逐渐取得全面绩效。这个时候对其进行超常规能力的测试,如果结果表明候选人已做好准备,就可以继续升职。这个测试可以通过让同一层级的领导者组成团队,完成一项高度挑战性任务来实施。

继任计划

继任计划是指在各级领导梯队中培养高绩效人员,确保充足的人才储备。整体思路是关注绩效潜能,适配公司的实际情况,定期审视领导梯队继任计划。

潜能上分3档:

  • 转型潜能:3-5年甚至更短时间可以从事下一层工作
  • 成长潜能:不久可以从事同一层级的更重要工作
  • 熟练潜能:可以更好完成当前层级的相同工作

从潜能和绩效两个维度,可以划分出9类员工。针对不同方格内的员工,着重培养领导力和提升绩效。

好的继任计划要求适用在所有业务和职能、贴合公司实际、可以公开讨论。

梯队的潜在缺陷

领导梯队也有遇到问题的时候,通常可能来自下面这些情况:

  • 选错人才
    • 在上一个层级做出成绩,不代表他的领导技能、时间管理、工作理念都已达到下一层级的要求
  • 让表现不佳者在岗位停留太久
    • 判断一名管理者是否还依赖上一级的领导技能、时间管理、工作理念
    • 观察管理者直接下属的职业发展和业绩
  • 不善于倾听反馈
    • 开阔心胸
    • 选择性听取
  • 不善于定义工作
    • 明确责任边界
    • 对齐责任边界

一个组织能需要有一个领导力框架,它能给绩效评估标准,提供更多的讨论问题的角度。通常一个团队内缺乏坦诚也是缺陷即将出现的危险信号。

职能主管发展路线

除了上面提到的领导力模型之外,还有职能方向的支线,即从集团职能主管到企业职能主管。集团职能主管和事业部总经理很像,但又不太一样:

  • 事业部总经理将智能战略纳入到整体业务计划中,但职能直观则将每一个事业部的职能战略纳入到集团整体的职能战略中
  • 两者都要有商业思维,职能主管也要从“我们能这么做么”转变到“我们这样做能赚钱么”
  • 职能主管通常同时向集团职能主管和事业部总经理负责,这需要他能灵活处理各种人群和利益关系,并且知道怎么妥协
  • 集团职能主管主要为集团高管提供咨询意见而不是产品和其他内容

作为集团职能主管,要避免出现下面的情况:

  • 给所有人承诺,却从不兑现
    • 集团职能主管要能够分解复杂关系,划清责任边界,获知业务优先级、自己优先级,最后做出果断的决定
  • 过度干涉职能部门经历的工作
  • 整天围着集团高管转

企业职能主管一般指CFO、CTO、COO、总法律顾问这些。他们的目的是将自己的职能和公司联系在一起,因此他们必须设定职能发展方向、学会服务整个公司而不仅是自己的职能、了解公司外部环境。要能满足下面一些要求:

  • 商业竞争中如何发挥职能的支持获得竞争优势
  • 了解所在职能在业界的发展状况
  • 向集团高管提供所在职能领域或一般性领域的发展机会

下面是一些对于企业职能主管的发展建议:

  • 尽早获取专家对职能部门的建议
  • 和CEO和各层级关键领导对齐你的目标和计划
  • 定期和各层级部门交流
  • 学会管理时间

教练辅导

教练辅导即用一种富有激励的方式,将上面的领导力模型指引给员工或是管理者。可以通过一些问题确定此人的领导能力、时间管理和工作理念:

  • 谈谈你的职业发展
    • 经历的每一个职务
    • 工作具体内容
    • 工作成就
    • 重大挑战
  • 现在职位的工作
    • 面临的问题、挑战
    • 取得的成就
  • 工作日程
  • 主要依靠的技能
  • 工作信念是什么
  • 职业抱负是什么

有些时候,自己进行教练辅导会比聘用不专业的教练要更好。

领导力模型惠及全员

--END--

流水账向絮叨文风,以纪念和嘉雯的第一次旅行

序:出发!

国庆节的出游通常都要提前一个多月计划,不过这次出游计划却比较仓促。由于某人的身体原因,我们在节前数天才定下这趟我期待了好久的出游。这一方面倒是让我在选择目的地上省了心,有很多之前计划去的地方,要么是去不了,要么是回不来。最终剩下广州、济南+青岛、济南+天津几个选项。报给对象看后,确定了这次山东之行。

既然定了地点,按我们的风格,三下五除二分工搞定了日程安排和机票住宿。对象继续赶工离谱需求,我回家当表哥伴郎。

Day 1:小吃

宽厚里、泉城广场

在表哥婚礼的第二天,我早8点从家里出发抵达遥墙机场,对象下午从上海出发抵达济南西站。本以为我会晚很多,没想到机场大巴一路绿灯甚是给力,我们干脆约在济南站见面。大巴到济南站时已近黄昏,“易立竞老师”还给我贴心地留了个麦麦脆汁鸡,啊这就是爱情。

济南站

易立竞老师

废话不多说,我们打车回酒店修整后,出发前往宽厚里。这是济南远近闻名的小吃步行街。我们一路骑车过来,正是晚上的黄金时间,路上交通拥堵异常(后来发现白天也拥堵)。小吃街也是人声鼎沸,摩肩接踵,每个看起来像是网红店的都排着老长的队伍。我俩大致逛了逛,小吃也没太多新意,奶茶店里,沪上阿姨、蜜雪冰城、冰雪时代几家尤其多。根据大众点评的推荐,我们排了个奶奶的美食,脆皮肠还不错。

宽厚里

也许是垃圾桶摆放不合理,街头的路面很脏,观感比较差。我们最终在一家鲁菜馆解决了晚饭。因为去得比较晚,经典的鲤鱼和大肠已经没了。剩下的菜里,鱼和虾都是酸甜口的,似乎鲁菜的口味都比较浓郁。

晚饭掠影

饭后已近10点,我们从泉城广场打道回府,夜里的广场端详不出明细,都是踏上归途的人。和对象在鸟屋旁一番神来般的交流,观赏鸽子的同时,不巧不远处有夫妻吵架。没待多久,我俩也知趣溜走。

鸟屋

Day 2:公园

大明湖、曲水亭街、芙蓉街、解放阁、黑虎泉公园、趵突泉

尽管地铁没那么方便,但是济南的核心景点距离都很近,可以骑车方便来往,公园基本上都无需门票,相当良心还是要夸一下的。由于距离酒店较近,我们从大明湖开始逛,这里更像一个大型的市民公园,无需门票。好在公园也够大,人流也就稀释得没那么密集,在国庆节期间体验还不错。湖面开阔,有零星游船。四周矗立着不少高楼,应和着绿树青天,有陆家嘴、曼哈顿公园那味儿了。

大明湖-1

大明湖-2

大明湖-3

只可惜天色多云,要不风景只会更棒。兜圈下来路遇超然楼,考虑门票价格后,弃之继续前行。最后从南门出来,前往南边的百花洲街区。

大明湖碑

从南门正对着的曲水亭街直走是大路,我们随便抄了条小道,迷迷糊糊摸到了临近的芙蓉街,很类似宽厚里,北京的南锣鼓巷,街边的美食和吆喝声让人头攒动的接到更加热闹。抵抗不住诱惑,我俩试了个豆腐和滕州菜煎饼,嗯……果然没太出彩。不过,在这么拥挤的环境下,路面卫生居然出奇得还行。

小巷

豆腐

滕州菜煎饼

从芙蓉街绕回曲水亭街后,我俩继续骑车,抄了一些小道后,我们到达临近宽厚里的解放阁。这里也无需门票,拾阶而上,在阁顶能俯瞰内城东南角附近。

小巷-1

解放阁-1

转瞬间,狂风大作,暴雨倾盆。幸好我俩带了伞。雨后的风光似乎被蒙上了一层灰,很是朦胧。

解放阁-2

解放阁-3

不远处,居然有一个露天泳池,在雨中似乎并没有受到积极性的打击。

露天泳池

解放阁下便是黑虎泉公园,据说泉水来自地下水,可以直接饮用。同样是不要门票,这里人也不少。我们来到才发现,这里其实不只黑虎泉一个泉,有不少泉眼,涌出的水注入到城河。这水清冽无比,以至于里面连小鱼都没有,若不是有气泡不间断珍珠般涌出,水面似乎像静止了一样。

白石泉

公园内水量最大当然也是最出名的莫过于黑虎泉。对于我俩这种从未见过泉水的人来说,可谓是大开眼界叹为观止。原来泉水还能涌出这么大的量,地下水这么多的么。泉边专门设有接水的地方,我尝了点,比矿泉水淡一些,又比白开水多一点味道。这里吸引了不少游客驻足。

黑虎泉

当然了,这里的两个题字也是妙极。

黑虎泉题字-1

黑虎泉题字-2

后续泉眼大同小异,人流不多,这里不再赘述。从公园出来正好又回到昨日的泉城广场,我俩又是一路骑车来到内城西南角的趵突泉,路上得以看到白天的泉城广场的模样。趵突泉需要40元门票,可以美团网上订票,可这并没有阻挡国庆节热情满满的游客。

趵突泉公园

趵突泉公园并不止有趵突泉这一头牌,它也是一组泉眼。这一点和黑虎泉公园差不多。

漱玉泉

卧牛泉

经过黑虎泉的洗礼,在见到趵突泉之前,我很好奇它是什么模样,可以如此出名夺目。不过见到后,不禁感慨还是自己年轻了。三眼泉水,左右两股更大,中间一股略小,但整体水量充沛。在平静的湖面上激起湍流,水质清澈见底,真乃奇观。直令人挪不开脚步。我俩驻足了有近半个小时。

趵突泉

泉水涌出的水汇聚后,流入到护城河中。

泉水

天色已晚,我俩骑车去了一家潮汕砂锅粥店,结束了一天密集的美景洗礼。

干炒牛河

Day 3:⛰和🍺

千佛山、老谢野馄饨、小褚烧烤

因为时间有限,这一天的旅程里,我们没有安排较远的山东博物馆和美术馆。决定在城南往事吃了午饭后去千佛山看看。午饭是正宗的鲁菜,我俩根据大众点评的推荐,里面下面这些:

  • 糖醋鲤鱼
  • 九转大肠
  • 油旋
  • 醋熘腰花
  • 水煎包
  • 老酸奶

基本没有踩雷,口味都较浓郁,适合稍重口一点的人吃。鲤鱼是这家店的招牌菜,店员还会帮忙拆鱼。油旋很香,不过分量也不少。酸奶里不知放了什么,口感十分特别,介于酸奶和老酸奶之间,很爽口。

城南往事-1

城南往事-2

解决午饭后,自然又是骑行去千佛山。爬山的前半程较缓,让我对它的高度产生了一些误会。根据我的观察,山应该得名于里诸多的佛像。

千佛山-1

千佛山-2

在历山院的半山处,可以俯瞰城区景观。经过一个名不副实的历山飞瀑后,再爬一段陡路就可以来到山顶制高点,这里风势略大,但是视野极好。不仅能尽览城区,起伏的丘陵也是一览无余。

历山院

俯瞰-1

俯瞰-2

天色不妙,我俩没在山顶待太久便下山打道回府,收拾行李准备前往青岛。在济南站,还吃到了满大街到处都有的超意兴,自助选餐,找到了大学打饭的感觉。顺便弥补了之前没有吃到把子肉的遗憾,不过,吃到第一口便发现,“不吃很遗憾,吃了更遗憾”。很油腻,我和对象俩人吃了一口不到。

超意兴

经过2个小时的车程,我们在青岛站下车。此时已近10点,我俩直接坐地铁来到江西路旁的酒店修整。稍微调整过后,还是决定出门吃个夜宵。既然是夜宵,又是在青岛。那当然是烧烤+啤酒没跑了。先暂时把体重的事情放一边。在大众点评一番寻找,我做了这个旅程最后悔的决定,去老谢野馄饨吃烧烤。这家店在大众点评上颇为火爆,他家的野馄饨据说美味且实惠。从下车开始,看到店门口茫茫多的人,不妙的兆头已经萌发。但“来都来了”,我俩还是硬着头皮尝试进店点餐。店内更是混乱,柱子上贴着需要自己寻找座位的字样,顾客非常多。坐下来吃的是少数,更多是坐下来等上串的,还要不少站在桌边等吃完的。画面甚是壮观。由于服务效率太低,管理也不好,桌面和地面上残骸不少。再加上有不知如何点餐的新人(就譬如我们),场面一片混乱。我抬手看了下表,难以置信这是晚上11点。

店里馄饨需要点,烤串需要自己挑选然后交给前台烤,啤酒也要自己打。店员很冷酷地告诉我们,目前烤串要等1个半小时,还好刚刚的糟糕情况给了我俩心理准备。一顿摸索,我俩来到了地下一层,这里稍微好点(可能因为有人不知如何下来),只是有不散的烟味。我们扫了码,和人拼桌,放弃了烤串,准备吃个馄饨就走。大概40分钟后,在主动抱怨下,终于吃上珍贵的12元馄饨。此时和我们拼桌,比我们还晚来的情侣已经吃完走人。

老谢野馄饨

馄饨汤的胡椒味很重,皮和馅儿很棒,很对我口味。不过对比漫长的等待和糟糕的服务质量,还是不值的。边吃,我们边寻找备选吃点喝点。结果发现巧合的是,这里距啤酒博物馆很近。最终在大多数已经关门的烤串店里,找到幸存的小褚烧烤。这家店离青岛啤酒厂的大门很近。我们要了一扎原浆。原浆未经过多的防腐手段,保质期比较短,因此也保留了更多发酵的菌群,朴实和清甜的口感未经修饰,是我喝过最棒的啤酒了。

青岛原浆

兴许是老谢的对比,兴许是真饿了,烤串也比我在北京吃的更棒。也算是一天的慰藉。酒足饭饱已经是第二天,幸在很好打车,回到酒店,对象倒头就睡。我洗罢衣服也睡下。

小褚烤串

Day 4:海和丘陵

开海海鲜、太平角、海水浴场、八大关、信号山、大学路鱼山路、小鱼山、五四广场、本家韩国菜

依旧是多云转阴的一天,我们甚至起得更晚了。出门时已近中午,我们干脆直奔五四广场的万象城。好在从江西路坐地铁去五四广场还比较方便。当初看酒店的时候,青岛因为旅游的属性,价格整体就要比济南高出一截。五四广场附近的就更离谱了。当然要是你财力雄厚,当然还是住在五四广场附近更加方便。

到达万象城的时候正是饭点,好在这里不像北京吃饭那么卷,大国庆的排队的人也还能接受。我们在溜冰场和附近的小吃城逛了下就到了。

万象城

来青岛自然要吃海鲜,我和对象错过了最好的季节,但也还是有的吃的。我俩事先做了下功课,根据我们的喜好要了:

  • 辣炒小鲍鱼
  • 辣炒蛤蜊
  • 海鲜水饺全家福
  • 锅烧碟鱼头

这几个算是这家的招牌了,剩下还有海参拌饭,捶山茄啥的就无福消享了。不愧是当地人推荐的店,除了鱼头,其他几个我觉得都很棒,鲍鱼很入味,蛤蜊的性价比简直超神。

辣炒小鲍鱼

辣炒蛤蜊

水饺全家福

锅烧碟鱼头

饭后坐两站地铁来到太平角,就可以沿着海岸线感受青岛的魅力了。沿海的栈道非常长,能够走好几天。海景自然也是赏心悦目,只可惜天色一片苍白。若是暑假过来,肯定是另一番美景。

太平角

海景

在和对象切磋过(基本是碾压)打水漂技巧后,我们顺路看了下附近八大关街区,街区较小,但是恰似青岛的缩影,上下坡不断,充分展示出丘陵的地形。这可能也是青岛没有共享单车的一大原因吧(电单车也没有)。

八大关-1

八大关-2

回到第二海水浴场的路上,偶遇的喵和花挽救了对八大关的失望。

吸猫

花-1

来海边除了打水漂,免不了还有戏水环节。对象身先士卒冲了下去。11月的海水,似乎也并没有那么刺骨。我还趁机尝了下海水。啊呸,果然是咸的。

戏水-1

戏水-2

时间有限,我们继续向第一海水浴场和信号山走去。一路可以轻易看到海天一线的景观,实在是悦目极了。

海景-1

海景-2

目前不是夏天,我们简单穿过海水浴场,开始了爬坡的旅程。在青岛旅游似乎总少不了上上下下。去信号山的一路也是如此,还很神奇的路遇大学路鱼山路的网红墙,不过除了俩路牌,我实在想不到可以网红的点。

鱼山路

信号山不大,也无需门票。山顶可以俯瞰红瓦黄墙,若再有蓝天晚霞那就太美了,很值得一来。

信号山-1

信号山-2

信号山-3

没过多久,天色变暗,气温下来。我们放弃了后续安排,下了山,计划坐地铁去五四广场。路上还看见了神奇的红色光环,喝到了中药味的崂山可乐。在冰冻加持下,似乎也没有那么暗黑。

光环

崂山可乐

晚饭依旧是在万象城解决的。吃的韩餐,青岛的韩国人挺多,韩式料理比较正宗。这个本家韩国料理也是当地朋友推荐的。石锅拌饭和冷面都还不错。

本家

饭后,五四广场是绝佳选择,这里是欣赏灯光秀最佳地点,诸多高楼的灯光拼凑出歌唱祖国的图样,红得耀眼。广场上,小商贩和城管玩着捉迷藏。

五四广场

夜景-1

夜景-2

五四广场西边还有个音乐广场,里面有些或好或惨不忍睹的素人演唱。晚10点,我俩来到网吧结束了忙碌的一天。战斗很愉悦,她也是。

Day 5:海其二

鲁迅公园、琴屿路、小青岛、栈桥、台东步行街、小褚烧烤

前一日行程受阻外加赖床,我们第二天果断放弃崂山,继续海边深度游。大概又是12点出门,我们这次的目的地是好美味馄饨店,尝试了这里的皮蛋、蛋黄馅儿馄饨以及微波烤串,还有某人从未吃过的火烧。馄饨和串的形式挺有意思,味道的话差强人意。

好美味馄饨

青岛城市里没有共享单车,我俩只能耐心地走到地铁站,再做地铁到人民会堂。在鲁迅公园和琴屿路的交接处再次与海重逢。

琴屿路

涨潮速度比想象中快,我俩险些被困在礁石上,对象还湿了鞋。附近的店里,洞洞鞋倒是不少,我挑了双明黄色的,还有小熊(๑¯㉨¯๑)logo,挺好看。

涨潮

礁石

天空阴云密布,海面也不平静。远处能看到搭载客人的游轮。琴屿路上,若是晴空万里,可能会更加好点看。

游轮

沿着琴屿路走到尽头,可以到达小青岛景区,小青岛的确是个岛,的确很小,也的确很绿。就是下图的左侧部分。

小青岛远眺

我们上岛时,天色已经不太作美。远远地,能看到我们的下个目的地——栈桥。同样的,阴天稍降低了些风景的美感。

小青岛-1

小青岛-2

还未到栈桥雨就下了起来,因为下雨栈桥上人不算太多。远远地,能回望到小青岛。

栈桥

海边的旅程到栈桥就基本到了尾声,我们在M记稍作休整,乘地铁前往奥帆中心。从这里可以获得和五四广场不一样的观赏夜景的视角。高楼灯光秀似乎也更对齐了一点。

奥帆中心-1

奥帆中心-2

从奥帆中心离开,我们慕名前往台东步行街。也有幸目睹了十分下沉的万达广场,找到了本世纪初的感觉。这块步行街的氛围和价格都很亲民,就像回到了老家一样。

台东步行街

今日的旅程又是以小褚烧烤作为结尾,虽没了第一天那么惊艳,但老板认出了我们是前天来过的,给了我们意外的优惠,还是很惊喜的。啤酒博物馆门外的啤酒街霓虹闪烁,也许这才有资格叫做灯红酒绿吧。

啤酒街

Day 6:尾声

失望的黄焖鸡

由于距离和赖床的双重作用,我们放弃了啤酒博物馆的日程,用黄焖鸡来为第一次一起旅行画上句号。最终在大幅降温前一同离开了青岛。

自拍

之前听人说,“情侣两人一同长途旅行一次,如果不分手,那么他们一定是真爱”。因为在计划阶段的行事风格,以及旅行途中的生活观念、饮食习惯、兴趣爱好等都是未来同居生活的小型预演,可以直接看出两个人的磨合程度。回头看,一起旅行的这些天,我们克服了一些困难,放弃了一些计划,也遇到了一些惊喜。尽管之前,我俩号称合体的晴天娃娃,这趟旅程却都是阴天和多云。不过问题不大,至少心情是漂亮的。相信这会是一个不错的开始,期待下次一同骑车长途旅行。

经历就会有惊喜

序:启程

自上次青海湖长途骑行,已经过去1年。这1年里发生了许多计划之外的事情,我优化了旧的喜德盛山地,拥有了新的闪电公路车,追求更佳的骑行体验。我减慢了更博文和读新书的频率,暂停了拉琴训练,腾出时间去追求人生的下一阶段,最后有惊无险最后遇到吕嘉雯,就像是老天对我一直以来坦诚相待的回报。扯远了,说回来,和基友约定的一年一次长途骑行还是继续。我们在7、8月份的骑行中就约定好大致的骑行目的地(江南沿海)和时间(中秋节)。青海湖骑行之后,我们患上了补给不足恐惧症,基友最终选定太湖,也是考虑到环湖下来都是大城市带来的优越体验。事后证明,这种安排让这次骑行带上了更多旅行的感觉。

Day 1 北京 -> 苏州

这次出发的时间碰巧赶上双减政策,让骑行得以宽裕地进行。只可惜对象要回乡下老家没能参与。我们选在中秋前最后一个工作日的晚上,做卧铺去苏州。

火车一大早到达苏州,我们住的酒店在观前街地区,算是苏州一个传统的购物步行街。7点多的步行街还没有什么人烟。所谓观前街,在步行街的核心地带有一个玄妙观。我们放下行李,在观旁的M记吃了顿早饭,作为旅途的第一顿餐食。

观旁边的M记

从观前街向东走过一个街区,可以到达平江路。在没那么商业化的角落,还是能感受到江南水乡的秀气。小桥流水,白墙黛瓦,一叶扁舟,绿柳蓊郁。我们在街巷中随意穿梭,故意做两只无头苍蝇。还无意中捕捉到好几家之前在小红书上看到的网红店。

平江路-1

咖啡店

我们来的时间也很巧,上午的时候路上人还不多,气温也很适宜。可以很舒服地慢慢散步扯淡。不得不说,小河的水利治理还挺不错,很少见到垃圾,水质也挺不错。

平江路-2

逛完城墙博物馆,我们兜了一圈又回到观前街,开启游客打卡模式,尝试了秃油黄面和三虾面,还有特色绿豆汤。面的口感还不错,很契合我喜欢吃细面的偏好。面口味偏淡,一碗100+,还不错但没到惊艳的地步。

秃油黄面

绿豆汤着实让人耳目一新,新颖的薄荷味配合冰水的温度让人感觉像是在喝漱口水。整体味道就是糖水口。基友没能坚持喝完,不怪他。

绿豆汤

在酒店稍作休整,我们继续启程,前往金鸡湖旁的国际博览园区。出地铁时,刚好赶上看夕阳的最佳时机。

落日

入夜后,这边商业区的风景要更为迷人。在诚品书店的屋顶,已近中秋的月亮分外亮眼。

诚品屋顶的月亮

当然,之前就有所耳闻的东方之门就更要打卡了,站在裤裆底下拍照的感觉还挺好玩。时间有限,山塘街我们最终没有去,算是小小的一个遗憾。

东方之门

回到酒店,时间大概是9点多,基友回了房间。我去附近一个网鱼网咖坐了会儿,居然发现以前还剩了30多元没用完,居然还有意外之财,真棒!

Day 2 苏州 -> 无锡

晒伤程度:0%

骑行的起点从湖边的一个国际青年旅社开始,一天100元,只有一种山地车可以选择,不提供驼包和车锁。可以肉眼看出的不专业。奈何太湖这边没找到其他像样的租车行,且湖边本来就离市区较远。我俩也没挑剔太多。付好500元押金,我们从环太湖大道出发。

天色不是很好,初到湖边还是比较有新鲜感的,微风吹过,吹散了骑行身上的燥热,还挺舒服。没想到,这也是这几天唯一逃过晒伤的一次。

环太湖大道-1

和青海湖边上的环湖东路不同,环太湖大道名不虚传,果然是十分贴近湖面,有些路段甚至直接修在湖面上。搭配着青山小河,景色妙绝。

环太湖大道-2

环太湖大道-3

简单在太湖湿地公园旁的农家乐吃过午饭,继续出发前往太湖大道,一路依旧在湖边前进。

太湖-1

快骑到无锡边界时,还能看到头顶的飞机。

无锡的飞机

经过一座跨河的桥,我们进入无锡市。远离了太湖,但是再次感受到令人安心的城市气息。

市界

夕阳路

最终沿着具区路骑行20公里,我们歇脚在江南大学旁的宜必思。简单地更换衣物后,正是晚饭时间,我们坐地铁进入城区,化身半日游的游客。在无夕小笼包店里简单地恰了心心念念的蟹粉小笼包和传说中的刀鱼馄饨后,我们来到小红书告诉我们最繁华的南长街南禅寺

蟹粉小笼包 & 刀鱼馄饨

类似的河,类似的巷,也许是因为门店的格调问题,或是路面修缮太过人工,我总觉得没有平江路来的那么自然和和谐。宽阔笔直的街道和河流,让它和之前在丽江大研古镇的旅行体验也有差距。当然热闹还是热闹的,也能勉强感受到江南小城的意味。

南长街-1

当然,中秋的月亮还是很不错的。在南禅寺大概逛了逛,我们打道回府,无锡的地铁线路相对比较简单,可以乘坐1号线直达。和苏州地铁一样,也许是人口不多,在中秋佳节的黄金时间,地铁里也能轻松找到位置,乘坐体验极佳,推荐地铁出行。

南长街-3

回到酒店,烘干好的衣服也好了。对比去年的青海湖骑行,体验好了太多。我们简单收拾下,便带着疲惫睡下。

Day 3 无锡 -> 宜兴

晒伤程度:80%

第二日天气好了太多,令人心情愉悦,再加上前日的阴天,让我忘记了关键的防晒。为悲剧晒伤埋下了伏笔。我们从江南大学旁的缘溪道出发,沿着高浪西路上山水东路便开始了晒足一天的旅程。

江南大学-1

江南大学-2

路线擦过无锡城区西南边缘,一路湖水树林,路况不错,风景更棒,尤其在鼋头渚附近。

鼋头渚

在环湖路锦园路交叉口,沿锦园路骑行可以获得更好的骑行风景。贴着湖边,有一个华东疗养院,附近的有不少钓鱼的人,风景很棒。

锦园路-1

锦园路-2

回到环太湖大道,骑一小段可以看到十八湾地质公园,省道路况甚好,当然阳光也甚好,骑过十八湾公园,爬一个长坡来到拐角,有一个缓下坡,边放坡边欣赏湖景的体验太棒了!迎面的清风,路面弯曲的美感,湖面的一览无余,踩踏的双腿似乎都已感受到慰藉不再疲惫。

放坡-1

放坡-2

放坡-3

离开省道进入常州市后,可以选择从雪雅线或者雪马路回到环湖路上,一路穿村而过,最后再太滆村回到湖边。

雪马路

太滆村

晴日下的波光粼粼让太湖看起来更有生气了一点。

波光粼粼的太湖

回到渎边线后,一路平坦笔直,日光毒辣,工业区属实没什么风景好看,一路狂飙后,在宜浦路交叉口朝宜兴城区逼近。

渎边线

宜浦路

经过范蠡大道交叉口,终于有种进入城区的熟悉感,没想到这是痛苦体验的开始,最后进城的几公里,地势上上下下,爬的坡比过往都还多。甚至于都没骑过平路。每当我以为,爬坡到此为止后。放坡结束又要开始下个煎熬。甚至于还有一个在上坡中间的红绿灯,把我虐够呛。一路折磨,最终来到龙背山——今日的终点。庆幸的是,今日宜必思的旁边又熟悉的沙县小吃,填补了我缺失的午餐。

宜兴没有很多好逛的地方,我们在八佰伴解决了晚餐后,踱步到东浗市民广场算是作罢。

东浗市民广场

结束一天的骑行后,通红的皮肤和洗澡时的刺痛,不时提醒我防晒的重要性。

Day 4 宜兴 -> 湖州

晒伤程度:150%

这天依旧是一个很棒的晴天,这次我开始考虑防晒的重要性。虽然我带了长袖,但是是黑色的且不透气,所以只能将就做好防晒就出发。今天的路线就更为简单,沿着浗滨大道来到G104国道,路过高铁站一路缓下坡,骑行体验甚好。

浗滨大道

在快进入浙江省时,还捕捉到了1314里程碑。

1314

快到省界前,是一个漂亮的爬坡,和很棒的湖景。

G104-1

G104-2

省界的里程碑也很有意思。

省界

在夹浦村岔路口,可以拐到滨湖大道上,让你一路湖景看到够,为了弥补前两天湖景的不足,我和基友不顾日头毒,毅然选择了这条路线。事实证明,我们的选择很正确。

滨湖大道-1

滨湖大道-2

整条路骑到湖州太湖度假区约20公里,当然一路没有太多树荫,一成不变的湖景看久了,显得稍有些枯燥。

滨湖大道-3

滨湖大道-4

所幸经过太湖旅游度假区后,几乎是一路下坡,骑行体验很棒,和昨日宜兴的进城之路形成了鲜明的对比。由于没有补充午餐,路上险些低血糖,幸好基友的月饼救了一命。

太湖度假区

一顿跋涉后,最终在下午3点来到银泰城对面的康铂酒店。

银泰城

在一顿海底捞弥补宜兴火锅被坑后,我们来衣裳街逛了逛,不出所料,是湖州版的南锣鼓巷,果然也有湖南臭豆腐和轰炸大鱿鱼,也不知大鱿鱼犯了什么错,要去轰炸它。也许是工作日,又也许是湖州并不是旅游城市,步行街里的人并不多,贴着市河一侧还稍微有点意境。

衣裳街

一日疲惫,我们走到兴尽,打车回府。

Day 5 湖州 -> 南浔

晒伤程度:180%

南浔是湖州的一个区,所以这一天的路程不算太遥远。姑且作为修整。沿着苕溪东路来到织里镇,可以拐到318国道上一路直行进入南浔。

苕溪东路

318国道从上海人民广场开始到西藏聂拉木县樟木镇中尼友谊桥。中间从成都到拉萨段也是很出名的骑行、徒步、自驾路线。这块里程碑表示距离上海市区只有136公里,比想象中居然近这么多。

G318-1

G318-2

由于只有30+km,中午12点多我们就抵达酒店。在一家猪蹄店大快朵颐后,我们回酒店休息到日头没有那么强烈,继续一个游客的使命。我也换上长袖,为过度晒伤盖上一块遮羞布。南浔区南浔古镇是较出名的景点,白日有乌镇的感觉,可惜我们来的时候已近饭点。古镇据说5点后不收门票,园内人数尚可,兴许是工作日的原因。南侧部分和平江路、南长街没什么太大的区别,北侧百间楼倒是有别样的韵味。在此处,河道渐宽,游客也比较少,还有一些原住民,有了江南水乡的感觉。

南浔古镇-1

南浔古镇-2

逛完古镇,在基友的期盼下,今天用海底捞画上句号。从海底捞打车会酒店,短短2公里,没想到滴滴也有人接单,看来还是在大城市呆习惯了。需要避免一些惯性思维。

Day 6 南浔 -> 苏州 -> 上海

晒伤程度:150%

由于湖州那天在滨湖大道上,已经连着看了20公里的湖景,再加上晒伤严重,最后一天我和基友不约而同选择了没那么沿湖的路线。基友率先出发,出了南浔区没多久,很快由回到江苏省境内。

江苏界

从318国道拐到258省道后,一路坦途。两侧既没有湖景,也没有树荫。

258省道-1

258省道-2

路过吴江大道后,我们又回到苏州,由于不确定省道能否左拐到东太湖路,我们从吴江区内绕路过湖,顺便做了补给。

江陵西路

沿着东太湖路一路向西可以回到环太湖大道,我们并没有向南去东山镇做更多的探索。回到熟悉的环太湖大道,心里的石头也落下了地。

环太湖大道

太湖大道上人并不多,我们还了车退了押金,也很轻松地叫了车进城。基友去宜家打卡,我去苏州站坐高铁去上海找对象。

三虾面

这几天我们是幸运的,车和人都没出意外状态,除了身上显眼的晒伤。脖子上明显的色差让我的脑袋像是后来组装在我的身体上。这次骑行过后,基友更坚信了我是他的吉祥物,和我一起来骑车,总能避免下雨和疫情。骑行前做的应急预案也很幸运地都没有用上。对比去年青海湖的受苦,这次骑行的风格明显更养生一点,每天不止能磨练筋骨,愉悦眼球,还能在疲惫过后享受现代科技的便利,无脑进入游客模式。体验可以说不能更好了。

在观前街分别前,我也祝福他十一环海南的旅途一路顺风。我们明年再见👋。

主干开发是相对GitFlowGithub Flow更贴合CI/CD(持续集成/持续分发)的高效版本控制管理实践,也更贴合Devops团队。

背景

在软件开发的早年期间,GitFlow和GithubFlow被用来在软件开发中做版本控制管理。

  • GitFlow工作流中,分为主干分支(master)、开发分支(dev)、特性分支、分布分支、热修分支等,这些分支都是长期存在的,并在需求开发完成/bug修复完成/代码发布等特定时候执行代码的CR(Code Review)和合码工作。且在合并时,由仓库的核心成员或者管理员们把握代码质量。随着项目的扩大,冲突的几率提高,每次代码合码时候的工作量也大大提升,带来了额外的仓库维护成本。Github Flow便随着Github逐渐流行起来。
    GitFlow
  • Github Flow工作流中,只有一个主干分支(master),一些特性分支以及发布时会用到的分布分支。开发者可以自由从主干分支签出特性分支开发、调试,并在需求完成后合入主干分支。一定程度上减少了长期存在分支的维护成本,但同样的,CR依然是项目管理者进行,特性分支合码时代码量依然有可能很大,团队内规范不好的话,也容易导致合码后主干分支不可发布。
    Merge Conflict

主干开发(Trunk Based Development)是一种更敏捷的git工作流,所有的开发者都可以合码到主干分支,结合CI/CD流程,有助于团队快速迭代。

什么是主干开发

主干开发和CI/CD相互依赖相辅相成。

  • 进行主干开发才能保证CI/CD,即每天充分多次的集成乃至发布
  • CI/CD过程中的快速自动化测试可以保证主干分支的可发布性

在主干开发中每位或者每小组开发者将自己的工作分成小份,然后以每天至少一次的形式从自己的分支合并到主干,由于每次合并代码量不大,CR时间以及CI时间都会缩短。一个典型的主干开发时间轴如下:

主干开发时间轴

在主干开发中,某些情况下需要从主干分支中选出最佳的bug修复合并到对应版本中,但如果每天发布多次,则根本不需要发布分支,可直接从主干中部署。这样做的最大优势在于减少开发线,频繁执行小批量合并,将代码保持最新。从而降低团队的合码成本。

如何实现主干开发

在进行主干开发时,开发者需要了解如何拆解工作为小份,同时,还需要让构建流程保持通过,如果CI失败,开发者需要立即停止当前工作修复问题,无法短期修复时,也要还原相应更改。通常来讲,主干开发有下面这样的特征:

  • 仓库里的活跃分支不超过3个
  • 分支的合码频率不少于每天1次,即分支的生存周期不超过1天
  • 没有代码冻结期或集成期

在实践中,有下面一些tips:

  • 小commit,多合码:将每次合码改动限制在少量的commit和较少的代码改动上,保证合码时轻松;主干分支应该有频繁的小批量改动合码
  • 最少1天1合码:每天合并或关闭待合并分支,有效减少合码压力,提高增量发布敏捷度
  • 同步Code Review:主干分支的每次合码需要保证CR的及时响应,这可以借助一些代码分析工具的辅助
  • 全面的自动化测试覆盖:确保有全面的自动化单元测试套件,保证测试通过后再合并代码,这也是保证主干分支可发布的基础
  • 构建快速:降低CI成本,构建和测试需要在几分钟内完成

同时也带来两个新概念

  • 分支抽象:在主干开发中,合码频率很高,有些大需求可能没有办法在1天内就完成合码,对于未完成的需求,可以在代码中先埋下未使用的新特性,等待需求完成后,再使用埋好的新功能。这种在源代码中提前埋下“代码分支”的方式成为抽象分支(Branch by abstraction)
  • 特性开关:在分支抽象的基础上,有些合并到主干的改动不一定想让所有用户都看见,可以在代码中预先埋入分支语句,再从配置中读取当前是否使用特性。这样可以实现功能灵活切换、实现ab-test等效果

feature-flags

标准开发流

1
2
3
4
5
6
7
8
git checkout master && git pull --prune
git checkout -b <feat/branch>
# coding
git push -u origin <feat/branch>
# after any updates
git push
# or add --force if rebased during updates
git push -f
  1. 更新本地master分支
  2. 签出特性分支
  3. 编码
  4. 推送本地分支到远端
  5. 提MR,如果MR后有更新,继续push,当rebase master遇到冲突时,推送需要增加-f参数
  6. 合码

注:因为主干开发每次合码量不大,建议使用rebase解决冲突

主干开发的好处

主干开发的最大好处在于对CI的亲和度。可以想象开发者完成当日工作,当日合码,当日测试通过完成集成,达到可发布状态。很大程度减少了合码的痛苦。进而有:

  • 持续CI
  • 持续CR
  • 持续CD

总结

非常适用于敏捷开发中,对于团队成员能力过关(要懂得怎样拆分需求)、测试有着良好建设的团队来讲,是种提效的好方式,值得一试。相反如果成员拆分不够良好、代码review不够及时,测试不够自动化和系统,则不适用主干开发。

参考

全文参考自马丁大叔的《架构整洁之道》,书中文笔清爽易懂,不过在后半段有点条理不清流于术而非道

在编程领域,问题就像一个生命体一样,是在不断繁殖和进化的。它甚至经常不会人们预期中一般发展。作为一名出色的软件工程师或架构师,你需要有超出普通程序员的视角,考虑系统宏观的未来的发展。你的使命是,在这种恶劣的开发环境下,绘制一幅相对最优的图纸,用最少的时间、人力、金钱构建和维护一个随时可能融化在熵增热汤里的软件系统。和现实物理世界里的架构师类似,你需要了解编程世界里的一般规律,帮助你挑选武器(技术),修炼秘籍(方法论),在不同的江湖里(业务)打造不同的门派(软件系统)。

开卷有益,祝你练武愉快~

你要做什么

简而言之,架构师的终极目标就是用最少的人力成本来满足构建和维护软件系统的需求。糟糕的架构设计会让软件在成功之前,就带来高昂的边际人力成本,即开发新需求的开支越来越大(因为程序员的时间都耗费在系统的修修补补上了)。然而,这种日益增长的边际人力成本现象并不少见。来源于类似龟兔赛跑中兔子的盲目自信,实际上,无论从短期还是长期看,胡乱编写代码的工作速度其实比循规蹈矩更慢

架构师存在的一个必要性就是,软件存在着两种价值维度:

  • 行为价值(现在时):即实现功能和弥补bug。这类价值是紧急却并不总是重要的
  • 架构价值(将来时):即软件是否足够“软”(易于被修改),这类价值是重要却并不总是紧急的

很现实的一点是,在公司中,团队之间的抗争本来就是无穷无尽的。你作为研发团队的一员,职责的一部分就是避免你的代码在抗争的风吹雨打下变成一坨没人爱的shit。

编程范式

没错,架构师们也有祖师爷。在1958到1968年期间,3大编程范式就已经陆续出现了。

  • 结构化编程,由Dijkstra在1968年提出,并发扬光大,它对程序控制权的直接转移(程序语句)进行了限制和规范
  • 面向对象编程,最早在1966年提出,Ole Johan Dahl和Kriste Nygaard注意到,函数调用堆栈可以被放到堆内存中,从而在函数返回后继续保留。它对程序控制权的间接转移(函数调用)进行了限制和规范
  • 函数式编程,启发自Alonzo Church于1936年发明的lambda演算,发扬于1958年的LISP语言。它对程序的赋值进行了限制和规范

值得思考是,三大范式做的都是限制和规范,即告诉我们不能做什么,而不是可以做什么。另外,多态带来的架构边界飞跃,函数式编程带来的数据访问限制,结构化编程带来的算法拆解为我们架构软件提供了强大武器。这也与软件架构的三个关注点所契合:

  • 功能性,即完整的功能实现
  • 组件独立性,即合适的耦合度与细粒度
  • 数据管理,即良好的数据结构设计

结构化编程

Dijkstra在1950年代思考编程时,得出过一个结论:编程是一项难度很大的活动。他倾向于把编程类比为数学推导过程,并发现goto某些使用会导致模块无法被递归拆解成更小的单元。然而,去掉这些使用的goto可以被顺序结构、分支结构、循环结构这三种最小集等价表示出来。从而,大问题可以被逐步拆解为小问题。

不过,事情也并非这么理想,当程序复杂后,我们不可能像Dijkstra一样,用严格的数学推导形式化证明编程的正确性。相反,类似实验学科的无法被证伪即正确,我们现今依旧使用着Dijkstra的结构化编程思路将大问题拆解为小问题。

有趣的是,“无法被证伪即正确”和Dijkstra的一个观点“测试只能展示bug的存在,并不能证明不存在bug”不谋而合

简而言之,去掉goto糟粕诞生的结构化编程中,最有价值的地方就是,它赋予我们创造可证伪程序单元的能力,从而架构起大程序。在架构设计领域,功能性拆解仍然是最佳实践之一

什么?什么叫做可证伪?你应该写过单元测试吧。

面向对象编程

什么是面向对象?有人说面向对象是“数据和函数的组合”,也有人说是“对真实世界的一种建模方式”。但这两种理解要么片面,要么虚无缥缈。为了总结这种范式,我们先从它的3大特征入手:

  • 封装,即将一组关联数据和函数圈起来。然而这种特性,从C语言起就支持(struct + 头文件),很难说它是面向对象编程的必要条件
  • 继承,即可以在某个作用域对外部定义的一组变量与函数进行覆盖。不过C语言也能模拟出这种能力,看起来也比较勉强。
  • 多态,即在同一接口描述下的不同具体实现形式,C语言起也做了支持(STDOUT),然而使用函数指针显式实现多态问题就在于指针的危险性。而面向对象编程对这种程序间接控制权的转移做了约束。

传统的函数调用树中,系统行为决定了自上而下的控制流,而控制流决定了源代码依赖(代码实现)是自上而下的,比如在C中会使用#include引入依赖。此时不论是代码实现还是代码执行都是自上而下的。然而在多态的帮助下,底层函数需要依赖高层接口实现,作为高层函数的插件引入,从而将这种依赖关系和控制流反向,即依赖反转。实际上,借助安全便利的多态实现,可以轻松将依赖关系反转。

从而架构师可以完全控制这种方式下,系统中所有的源代码依赖关系,进而随意更改源代码依赖关系。让每个组件都有独立部署独立开发能力。好了,我们现在可以说明面向对象编程的含义了:

面向对象编程就是以多态为手段来对源代码中的依赖关系进行控制的能力。这种能力让架构师可以构建插件式架构,让高层策略性组件和底层实现性组件相分离。借助接口,底层实现性组件作为插件,可以独立于高层组件开发和部署。

函数式编程

函数式编程依据的原理早在编程之前就已出现,相对前两种范式,函数式编程的风格可能相对陌生一点。在这类风格中,变量都是不可变的。从而让竞争问题、死锁问题、并发更新问题不复存在。一个架构良好的系统,需要将状态修改的部分和不需要修改的部分隔离开,然后用类似事务型内存的方式来保护可变量。另外,架构师应该着力于将大部分逻辑归于不可变组件中,可变组件的逻辑越少越好。

书中还提到了只包含CR的事件溯源存储逻辑,即通过事务日志的方式保存当前状态。因为不存在更改和删除,从而不存在并发问题。也是一种很新颖的思路。

回顾上面的三种编程范式,都在说什么不应该做。也即编程好似在充满死路的熵增旷野中,只有沿着相对安全的几个大方向才可拨开迷雾。

设计原则

软件的中层需要具有良好的可读性、可扩展性。这里就不得不提到SOLID原则:

  • SRP:单一职责原则,每个模块有且只有一个需要被改变的理由
  • OCP:开闭原则,对扩展开放,对修改封闭
  • LSP:里氏替换原则,子类型应该能够无无缝替换类型使用
  • ISP:接口隔离原则,依赖的模块不要包含不需要的接口
  • DIP:依赖反转原则,高层策略性代码不要依赖底层实现性代码

SRP

任何一个软件模块(一组紧密相关的函数和数据结构)都应该只对一个行为者负责。实际上,代码和数据就是靠着和某一类行为者的相关性组合起来的。我们需要将服务不同行为者的代码进行切分

OCP

设计良好的软件应该易于扩展,同时抗拒修改。实现方式可以通过将系统划分为一系列组件,并且将依赖关系按层次组织,使得高阶组件不会因为低阶组件修改受到影响。

LSP

里氏替换原则表示,子类型应该能够被当做父类型使用。它实际上表示了一种面向接口设计的设计原则。一旦违背了这种可替换性,就会不得不在系统架构中增加大量复杂的应对机制。

ISP

ISP告诉我们任何软件设计如果依赖了不需要的东西,都是不好的迹象,很容易带来不必要的麻烦。

DIP

DIP告诉我们,应该多引用抽象类型,而不是具体实现。因为软件是经常变动的,而抽象出共性的接口则是较少变化的。从而可以衍生出一些守则,譬如:

  • 应该多使用抽象接口,避免使用多变的实现类
  • 不要在实现类上创建衍生类
  • 不要覆盖具体实现的函数

不过当然了,还是得有人做实现的脏活累活的

组件构建

组件

组件是构建软件的最小单元,同时也是源代码的集合。在早期会使用链接技术将程序和库函数链接起来,而后随着机器性能的增长,我们会在程序运行中插入动态链接文件,如今这种组件化插件式架构是最常见的软件构建形式。

组件聚合

和类相似,组件也有一些原则指引我们的构建工作。

  • REP:复用/发布原则,即可以一起发布的最小粒度就是复用的最小粒度,也即按可以同时发布聚合
  • CCP:共同闭包原则,即因为同一原因修改的放在一起,反之不要放在一起,也即按变更原因聚合
  • CRP:共同复用原则,即会被一起复用的放在一起,反之不要放在一起,也即按减少无用耦合聚合

这三大原则相互牵制,在项目的不同阶段,某一原则重要性也会不同;比如在项目早期CCP就会更重要,而后REP会比较重要。

组合耦合

本节提出了一些可以定量衡量耦合健康度的指标,比较新颖。

  • 无依赖环原则:依赖关系中不能有环,会不利于厘清依赖关系;可以通过依赖反转创建第三方依赖组件解决。循环依赖关系务必持续监控。
  • 稳定依赖原则:依赖关系必须指向稳定的方向,简单点说就是让经常变更的组件依赖于不经常变更的组件。一个组件的位置稳定性可以通过入向和出向依赖算出,它要能和组件的实际稳定性匹配。
  • 稳定抽象原则:抽象化程度需要和稳定性程度一直,即经常变更的组件要容易变更,即更具体实现;反之,稳定的组件要不容易变更,即更抽象。结合上条看,依赖关系应该指向更抽象的方向。

使用位置稳定性指标I和抽象程度A,可以绘制一个坐标系。在主序列上的是最健康的,相反的两块痛苦区和无用区则是不健康的表现。用偏离主序列线的距离可以大致衡量依赖关系的健康程度。结合发布版本的变化来看,还可以得到变化趋势。

软件架构

软件架构目的就是方便在工作中更好地对组件进行研发、部署、运行和维护。其中的策略就是保留尽可能多的可选项。让系统最大化程序员的生产力,同时最小化系统运营成本:

  • 开发:系统架构需要方便开发团队对它的开发,不同的团队结构应该采用不同的架构设计,比如团队的大小就会影响架构的选择
  • 部署:一键式部署
  • 运行:几乎任何运行问题都可以通过增加硬件来解决
  • 维护:减小新功能和系统缺陷占用的人力资源

保持可选项,忽略那些无关紧要的实现细节。任何软件系统都可以拆解成策略(业务的宏观逻辑和流程)和细节(具体操作行为)。而策略才是系统的真正价值所在。细节是指那些和策略交互的东西,包括:

  • I/O设备
  • 数据库
  • Web系统
  • 服务器
  • 框架
  • 交互协议

在设计时,可以尽量拖延上面这些的设计,这样我们做出的决策才不会依赖各种很容易变化的信息。另一方面,也可以增加实现底层的可替换性。举个具体例子:设备无关性

独立性

一个良好的架构应支持下面几点:

  • 系统用例:设计良好的架构需要能够看起来就可以反映系统的设计意图,比如一个购物车应用架构应该看起来就该是用来实现购物车的
  • 系统运行:可以解耦出多个独立服务,然后通过某种网络协议通信,这种架构即微服务
  • 系统维护
  • 系统开发
  • 系统部署:理想的独立部署应该能够做到热更新

要注意留意表面的重复和实际的重复,如果两段代码变更速率和缘由不同,那么就不算是真正的重复。

划分边界

  • 设计良好的系统架构不应该依赖细节,而应该尽可能推迟细节性的决策。通过划清边界,可以推迟和延后细节性的决策,从而节省大量时间,避免问题。
  • 边界线应该画在不相干的事情中间,譬如GUI和业务逻辑
  • 针对核心业务逻辑的插件式架构可以提高可维护性和可扩展性

边界剖析

简言之,应该尽可能从底层组件指向高层组件。

策略和层次

  • 变更原因、时间和层次不同的策略应该属于不同的组件
  • 按距离系统输入、输出距离的远近,可以确定策略的层次
  • 源码间的依赖关系,应该主要和组件所在的层次挂钩
  • 低层组件应该以插件的方式依赖高层组件

业务逻辑

业务逻辑是程序中真正用于或者体现赚钱/省钱的逻辑与过程。其中关键逻辑和关键数据紧密组合成为业务实体。业务实体应该只有高层逻辑,没有具体实现。而用例是业务实体在不同侧面的具体体现。通过用例可以规范用户和业务实体的交互方式。

“尖叫”的软件架构

“尖叫”即所见即所得。软件架构本身就足以能够体现其用途。一个良好的架构设计应该围绕用例展开,推迟和延后框架的选择,不要过度拘泥于框架。框架只是一个可选项,是一个工具,而不是一种信念,更不是一种架构。

整洁架构

一些常见的系统架构通常具有以下特点:

  • 独立于框架
  • 可被测试
  • 独立于UI
  • 独立于数据库
  • 独立于外部接口

Main组件

  • Main组件包含了系统中最细节化最底层的策略,它应该在做完脏活累活后,将程序的控制权交给最高抽象层的代码去执行
  • 针对不同系统可以配置不同的Main组件,即将Main组件视为应用程序的一个插件

服务:微观和宏观

  • 系统的架构边界事实上并不落在服务之间,而是穿透所有服务,在服务内以组件形式存在
  • 服务可以提升系统的可扩展性和可开发性,不过服务却并不能代表整个系统的架构设计

整洁的嵌入式架构

  • 固件即对平台或硬件的强依赖代码,在固件和软件之间可以设置HAL(硬件抽象层),为它上层的软件提供服务,它可以帮助软件脱离目标硬件平台来测试
  • 类似地,我们还可以引入OSAL(操作系统抽象层)来减少软件对操作系统的依赖

实现细节

那么什么算是实现细节呢?

  • 数据库,数据的组织结构和模型都是系统架构的一部分,但是从磁盘中存储/读取数据的机制或手段则没那么重要,就比如数据库或静态文件
  • Web,Web只是UI,只是一种I/O设备
  • 应用框架,框架被创造的目的是解决作者遇到的问题,它要求我们去阅读文档,按照作者的要求整合到我们的应用中,可以使用但是不要被框架绑定

案例:视频销售网站

  • 系统架构设计的第一步是识别系统中的各种角色和用例

–END–

0%