Nullts's Blog


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

不仅仅是敏捷开发-读《深入核心的敏捷开发》笔记及读后感

发表于 2020-04-27 | 分类于 中台 , 敏捷

0x00 题记

敏捷其实上学就听过,scrum、XP等等,但上学没有经历复杂的软件项目实施,对软件工程的很多概念和规范是浮于表面,知其然,不知其所以然。然后最近有几个事一直和“敏捷”相关:

  1. 去年在阿里数据中台培训时,讨论到数据中台的开发模式,阿里教练说,数中是无法用“敏捷”方式的,但至于他们用了什么样的模式并没有说;

  2. 我们在对一个客户在做BI实施时,由于他们的业务交付团队一直用敏捷的方式交付的,所以也需要我们用敏捷交付,当时由于第一点的原因,我是反对且内心是抗拒的;

  3. 公司在讨论数中我们到底用什么模式开发时,在说到底是“瀑布”还是“敏捷”,突然觉得这件事是需要想想的;

  4. 再看中台相关时,由于会很多地方带上“敏捷”的讨论,我突然想如果第一点是错误的呢?

所以我需要对敏捷做一定了解,再做判断,恰巧看到了Thoughtworks出版的这本书《深入核心的敏捷》,帮助我了解敏捷开发,这本书也确实没有让我失望,为了开了一扇门。

0x01 核心原则

1.起源

2000年前,软件交付项目的失败或交付困难的比例很高,很多牛逼的软件开发者不满意瀑布软件开发的方法做交付,在各自工作实践中用了很多方法,涌现了很多新的软件开发方法。2001年17位软件大师在犹他州的小镇雪鸟,总结了当时涌现的开发方法所具备的特点发布了“敏捷宣言”。让我们再回顾他们:

image-20200428224505848

敏捷软件开发宣言

我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观:

个体和互动 高于 流程和工具
工作的软件 高于 详尽的文档
客户合作 高于 合同谈判
响应变化 高于 遵循计划

也就是说,尽管右项有其价值,我们更重视左项的价值。

2.敏捷宣言到底有几句?

六句!但大家大都记住了中间四句,我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观这句话告诉我们敏捷宣言是不断实践中总结出的价值观,价值观不是具体实践的目标和实践,而是价值取向。所以有的团队说,我们敏捷了,因为我们做了迭代开发,这种单纯的实践=敏捷是不成立的,我们需要多维度了解团队的价值观知否符合敏捷的价值观。

尽管右项有其价值,我们更重视左项的价值。这句话是敏捷宣言中最重要的一句,在敏捷过程中,会有这种现象:“敏捷说了不需要文档,所以我们以后不用写文档了”,“敏捷说了不需要计划,那我为什么要给计划”,这些都是敏捷转型方向上的错误。宣言中价值观用了“OVER”(高于),A高于B,并不是用A舍弃B。当初17位大牛,早就遇见到这样的问题,所以用了最后一句话强调,并不是让我们要舍弃右项实施左项。

3. 开发人员的客户思维

作为开发人员,很多人有“技术至上”的自负心理,这都是与他们理工科的成长背景有关系。“因为,所以,得证”,这是数学里常见的论证不走。但事实却不会这么简单。一个需求,必定有商业和业务上的考量,在实现过程中,还需要考虑不同的解决方案,各个方案中存在的风险和投入成本。对业务理解的一致,所有努力朝一个方向,才能获得成功。

在现实中,客户由于对技术和实现方式的不了解,经常challenge我们,会不专业,也不油耗。我们会时常会在内心质疑客户,但他们不是第一个,也不会是最后一个,但我们要思考的是客户为什么会这样,他们是为了解决问题的,并不希望项目的失败。数字化的技术、交付组织只会越来越复杂,如何教育我们的客户更是一个大话题。

引用书中的一个故事,让我们谨记客户思维的重要性。当我们为了谋生而一头扎进代码的世界里时,其实与小时候老家镇上铁匠铺的铁匠并没有区别。那样的我们,不用顾虑顾客为何需要打造那么一件奇形怪状的铁器;在顾客一而再地提出挑剔意见时,我们一开始争辩,后来丧气,最后麻木了。那样的我们,数十年如一日,作为铁匠的技艺愈加成熟。直到有一天,一种叫“铸造机床”的远在天边的东西,夺去了我们的饭碗。

0x02 核心实践

1.专业团队、自组织、带头人

作者在书中从一次汽车贴膜看专业团队的专业服务。所有工作高度被高度并行化。四个人同时施工,一个人在缝真皮方向盘套,一个负责贴车左侧窗户的膜,一个负责贴右侧的膜,一个负责贴前后挡风的膜。其次,大家没有清晰的角色划分,缝方向盘的人在完成手头工作后,会立刻加入贴膜的工作,贴膜完成后,两名工人开始帮车打蜡和内饰清洁,整个过程自然而连贯,完全自组织,不需要人安排和监督。所有人都掌握了整套技能,并没有严格的分工,整个过程已经被高度优化过,环环相扣,环环相融,无论时间还是材料的浪费都被降到最低。

在做“新车去异味”项目时,一头扎进充满延误车厢的人是这家店的老板,是的,他还是上面四人之一。在作者看来是一个称职的带头人。凡事冲在前面,以身作则,勇于承担一些困难甚至危险的工作。而作为客户的作者,自然也对这个团队平添了一份信任和钦佩。

2.团队的精进之道

当我们带领一个团队时,我们想的总是,如何做好任务分配,平衡战斗力和交付最好结果。于是,我们下意识简单的因才分工,随着项目的进展和人员流动和意外的发生,项目后期会处处制肘,以加班以示诚意。作者在工作中遇到一个高人,他在项目开始的时候,问清楚每个人擅长的部分,然后让每个人去做自己不擅长的部分,不会?去找擅长的人帮忙,虽然看起来有点乱,但他负责的项目从来没有出问题。这是“把项目成功交付看作能力建设副产品”口号的一种朴素实现。

很多团队能力不强,团队的领导就总是在向外寻求方法和帮助。这个行为本身没错,但是做这件事的人无法摆正心态,很多人潜意识是假设团队成员能力不变的,期待在此前提下通过一种魔法般的方法改变团队绩效,这种思路在真实世界中是走不远的。在Thoughtworks、认为,软件开发中的一切问题,根本上都是人的能力问题。如何发展每个成员才是关键问题,我们采取的一切实践,核心目标只有一个:发展人的能力,所以才有耸动的口号:“把项目成功交付看作能力建设副产品”。

一个人要划任务、估时间、在做的时候计时、根据实际结果进行反思。我们可以把这个方法做成非常邪恶的、仿佛流水线上工人的强制要求。我们不关心员工为什么超时,就通过这种方法控制程序员,要求每个人按照一个死板而讲话的步骤做一些简单重复的机械动作。也可以用这个方法来锻炼一个人自我 认知和发现知识漏洞等能力,促使他快速成长,等他成长起来马上给他更重要的任务。这两种结果的差异,背后是领导者认知的差异、团队成员认知的差异。作为敏捷宣言里的一句话表达出来:“个体与交互 高于 流程和工具”。团队流程和工具,是为了成就个体,促进交互?还是为了抹杀个体,消除交互?这微小而关键的差异,是一切的本质。

3.需求风险的坏味道和对策

<1>识别坏味道

软件工程是一件专业性很强的事情,我们必须教育客户,让他们明白管理软件项目,有很多场景我们也经常遇到:

“这个需求我们实现过,只需要一周时间就可以完成。”

客户正在插手工作量的估计,这是最危险的,我们应该让客户完全了解我们的工作量估计系统是如何工作了,要强调我们的工作量合理、公平、有效

“关于这个需求,你做个方案给我选一选。”“这两个方案我都不喜欢,要不你们再想想”

这代表客户不理解在软件开发中,“需求分析”也是工作量的一部分,AB稿在设计界广泛存在,并且作者认为是低效的决策方案。

“这是领导要的,我也没办法。”

客户正在抛开自己的决策责任,尝试用最不负责任的方式逼迫你答应需求。

<2>对策

  1. 尽可能靠近决策者

  2. 做系统决策人

  3. 不要给选择

  4. 管理结果而非解决方案

  5. 建立游戏规则

4.结对编程

极限编程中的极限是指将我们认同的有效软件开发原理和实践应用到极限,如果集成测试很重要,那一天多次集成,反复的进行回归测试,所以我们要做持续集成,如果代码评审很重要,所以我们要一直进行代码评审,所以我们要做结对编程。

设计和编程都是人的活动,忘记这一点,将会失去一切

结对编程的好处:

  1. 培养新人,促进沟通,提升团队整体能力;
  2. 更好的知识共享和信息交流,促进团队协作;
  3. 促进团队成员的沟通,提升凝聚力。

5.站会

说到站会,就会有三个经典问题:

  1. 昨天完成什么
  2. 今天准备做什么
  3. 遇到什么障碍

当团队养成随时沟通的习惯后,站会还有存在的必要。站会总是有人迟到,吃早饭,玩手机,我们还需要站会吗?从团队发展阶段模型,团队发展一般需要依次经历几个阶段:

  • 组建期
  • 激荡期
  • 规范期
  • 执行期
  • 休整期

站会在每个阶段承担着不同的作用:

组建期和激荡期:建立信任

规范期和执行期:关注价值流动

执行期:仪式感

敏捷不是遵循“最佳”实践,而是要搞清楚实践在什么环境下解决什么问题,然后再合理地对实践进行裁剪和改进,这才能保持敏捷力。

6展示会的七宗罪

  1. 准备工作没做好;充分做好准备工作
  2. 没有上下文铺垫;开始演示前先介绍上下文
  3. 逐条过AC;以功能为单位演示
  4. 企图覆盖所有路径;只演示关键路径
  5. 过多提及跟演示无关内容;只提及要演示的功能
  6. 认为展示仅仅是BA或QA的事情;人人都可以展示
  7. 不熟悉的新人负责展示;展示前先充分了解系统和业务

0x03 管理体系

1.Scrum

<1> 三个角色

角色一:PO的任职资格

在作者见过的Scrum团队中,绝大部分PO是不具备做PO的资格,不是说能力,而是资格。PO从职责上讲拥有,Product Backlog,负责决定哪些功能进,哪些功能不进以及优先级是什么,是必须有资格能够负责产品的方向。换句话说,PO通常是资方而不是劳方的人,PO要么给项目提供资金,要么是他的代言人。

角色二:Scrum Master的悖论

Scrum Master的使命就是把自己做没,这个角色深刻反映了Scrum内在不一致。如果Scrum Master做得好,他会把自己的大部分工作做没,变得越来越轻松。按照Scrum Master定义,从根本上上是一个教练的角色,教会自组织、教育po、教育开发团队,教育其他干系人,评价教练的唯一标准就是被教的人不需要他

角色三:开发团队自组织的假象

<2>四个会议

Sprint 评审会

如何评价评审会的效果?唯一的标准是,会后有没有对Backlog做出调整

Sprint计划会

实际上应该分开两个会IPM、IKM,讨论做什么和如何做

每日站会

最流于形式的会,成为类似考核会一样,考量工作是否饱满,大家证明自己没闲着。应该关注什么?进度、障碍、新知及是否要进行调整,关注的是接力棒而不是运动员

Sprint回顾会

2.敏捷实践

剑道中有这样一个心决:守,破,离。

  • 守:最初阶段须遵从老师教诲,认真练习基础,达到熟练的境界。
  • 破:基础熟练后,试着突破原有规范让自己得到更高层次的进化。
  • 离:在更高层次得到新的认识并总结,自创新招数,另辟新境界。

0x04 转型

1.敏捷转型的三个阶段

阶段一:建立敏捷流程,缩短交付周期;这个阶段主要目标是将需求反馈、开发质量反馈、以及改进周期缩短在一个迭代内。

img

阶段二:引入技术实践,质量内建,减少返工;这个阶段主要目标是提升开发人员意识,从而提升开发阶段产出的质量水平,减少后续环节的返工。

阶段三:提升价值交付效率和响应力;这个阶段目标就是培养成员的自我提升意识,软对的自我改善能力,并帮助团队建立自我改进习惯

img

2.绩效考核,敏捷转型鸿沟

绩效考核,绩效排名以及年度考核是管理上七大顽疾之一。

传统绩效考核与敏捷价值观间,在对象、目标、考核周期、考核结果、负责人都有巨大冲突。绩效考核的目标,本质上就是如下问题:

  1. 如何决定给员工涨多少薪水?
  2. 怎么决定谁应该升职?
  3. 怎么决定谁应该被解雇?
  4. 员工如何能知道他们需要做得更好并努力提升自己?

真正高绩效的员工,未必为了金钱而工作,最能激励他们的是有挑战的工作和合理的自主权。通过对于产品价值、质量交付及交付效率的度量,透明公开可视化这些指标,更容易激励员工做得更好。

img

正如《管理3.0:培养和提升敏捷领导力》所说,所有变革最后的失败都是管理的问题对于转型中的组织,特别是一线管理人员,应该把绩效考核这种管理手段当成“敏捷铁三角”中的一角来对待,那就是调整约束。把它当成跟时间、成本、资源等类似的约束因子来统一管理。一家企业之所以存在,有其独有的文化和运作规则,只有调和好约束,才能最大化敏捷的价值,如下图所示

img

0x05 案例

1.技术决策

作者在书中的案例,由于一个自制存储框架的“鲁莽”技术决策,本身一个很重要的决定,却没有拿到台面上和客户讨论。通过很尴尬的和用户解释为什么从一个自制存储框架到成熟的存储框架。客户虽然不高兴,但认为佐证正在改善这些,开始设立技术治理小组,进行讨论,积极的应对技术债。

技术领导者的倾向从追逐“正确”的决策,变成开始作出“合适”的技术决策。

我们应当让客户参与到技术决策中,团队做出决策,承受自己决策的后果,但是和客户更多的分享上下文,客户保留否决的权利。如果客户不认可,分享原因后,团队可以更好的提出别的方案

2.工程师文化

<1>工程师文化与kpi文化

  • 工程师文化是由内而外的引导和自然发生,KPI文化是由外而内的信仰和强行注入;
  • 工程师文化着眼未来, KPI文化活在当下。
  • 工程师文化痛恨KPI,我不爱的我不做,我爱的我疯狂。 KPI文化唯KPI说话,爱不爱都要像战士一样完成。

<2>工程师文化的前提条件

信任:leader和产品对工程师绝对的信任是工程师文化的最基本条件。如果他说要用一个更优雅的方法解决一个问题,但要花更多的时间,请你选择相信他。好的工程师非常懒惰,他这么做一定是为未来的工作提高效率。

卓越的技术领袖存在:领导如果对技术没有信仰,只把技术当成工具,就很难说这个团队会有工程师文化。说白了不是每个不懂技术的领导都懂得欣赏优雅代码产生的美和对未来产生的深远影响。

技术列为KPI:参加晋升面试的时候,50%以上的技术人员讲的都是产品(what),而不是技术(how),并且他们都晋升了…..这源于业务BU总是把业务当成KPI的唯一衡量手段:技术好不好有什么关系?今年不出事,明年我已晋升。如果没有技术KPI,技术就会总被放在次优先级。

0x06 读后感

其实看完正本数,依然要重读第一章,应该深刻记忆敏捷宣言,记住他是一种价值观,而不是一种实践,在每个项目中我们都应因地制宜的制定自己的敏捷策略,最佳实践永远都是一种参考。

了解完敏捷后,突然发现敏捷和中台的很多目标都是互通的,都是在加强自己的“用户响应力”、技术即业务、中台的理念更像是把敏捷的思想从一个交付团队上升到了企业级,这其中不仅仅只有工程师组织,还有更多业务和商业上的考量。

对敏捷的了解还是浮于表层,希望以后可以在实践中践行敏捷价值观。

浅入浅出“中台”

发表于 2020-04-25 | 分类于 中台

0X00 题记

“中台”的名字大概听了一年有余,其间参加了阿里云的数据中台培训,当时更多的记住了技术层面的事情,对“中台”两个字的理解其实没有超出“中间的平台”的认识。“中台”听到的越来越多,中间很长一段时间只是把他当成某种技术方案别名。最近一直很多关于中台的问题都未想通,找了很多材料,阅读了很多文章,略有心得,找到点“看山还是山,看水还是水”的感觉,现串联整理并加一些自己的感受成文。Headfirst是深入浅出,我就浅入浅出“中台”。

在这需要感谢“Thoughtworks”的文章,很多未想通的问题都是他们的insight让我醍醐灌顶。“Thoughtworks”是第三家让我由衷崇拜的公司,第一家是google,第二家是spaceX。

0x01 WHY

1.中台如何而来

追述下“中台”的来历,江湖上传闻最多的应该属阿里巴巴的版本了(好像也就一个版本)。话说 2015 年底,马云到访芬兰参观了 Supercell 游戏公司,学习所谓的“大中台架构”,据此调整阿里巴巴的组织结构,以避免了大公司常见的部门与部门争夺资源,不同的小组做同样的事情。回到国内不久,阿里巴巴就启动双中台战略——大中台小前台。

Supercell将120人的产品团队,拆解为20多个自主管理的小团队,从而降低管理成本、提高团队协作效率一家仅有300名员工,却接连推出爆款游戏,是全球最会赚钱的明星游戏公司。
在Supercell,一个游戏通常4-5个人研发,Supercell面向全球市场推出了《部落冲突》、《卡通农场》、《海岛奇兵》和《皇室战争》都是爆款游戏。

image-20200424105944001

再后来到处都在喊中台,到处都是中台,中台这个词在我看来已经被滥用了。

  • 在有些人眼里:中台就是技术平台,像微服务开发框架、Devops平台、PaaS平台,容器云之类的,人们都叫它“技术中台”。
  • 在有些人眼里:中台就是业务/数据平台,像最常见的什么用户中心,订单中心,各种微服务、BI集散地,人们都叫它“业务/数据中台”。
  • 在有些人眼里:中台应该是组织的事情,这类组织中台在企业中主要起到投资评估与投后管理的作用,类似于企业内部资源调度中心和内部创新孵化组织,人们叫它“组织中台”

说很多,但最终还是有这几个问题,我们需要面对的

中台到底是什么?它对于企业的意义到底是什么?当我们谈中台时我们到底在谈些什么?

前文一直在说“中台”,我接触到中台的时候,也一直在“中台”的范围中转圈,并没有从一个企业的视角去思考,并不是所有的企业都是阿里、supercell,投入如此重、甚至重购整个组织的中台,到底有什么价值。有了新的两个问题:

  1. 企业为什么要平台化?
  2. 企业为什么要建中台?

<1>企业为什么要平台化?

不断快速响应、探索、挖掘、引领⽤户的需求,才是企业得以⽣存和持续发展的关键因素。

那些真正尊重用户,甚⾄不惜调整⾃己颠覆⾃己来响应⽤户的企业将在这场以⽤户为中心的商业战争中得以⽣存和发展;⽽反之,那些在过去的成就上故步⾃封,存在侥幸⼼理希望⽤户会像之前一样继续追随⾃己的企业则会被用户淘汰。

image-20200424135434427

平台的最重要是它赋予或加强了企业在以用户为中心的现代商业战争中最最最核心的能力:⽤户响应力。这种能力可以帮助企业在商战上先发制⼈,始终抢得先机。

这么说比较虚,什么是用户响应力,举个栗子。疫情期间,我们需要百来号的人一起线上会议,钉钉快速响应企业这一需求,快速提升原有视频会议最大容量。这就是钉钉将⾃己的技术和业务能力沉淀出一套综合能力平台,具备了对于前台业务变化及创新的快速响应能力。天下武功,无坚不破,为快不破。

“用户响应力”,这五个字是我理解中台的第一步。

<2>企业为什么要建中台?

说中台,先对前后台做明确:

  • 前台:企业前方市场的前端平台,是企业的终端用户直接使用或交互的系统。比如像微信、QQ、淘宝这样的APP、电商、内容等网站;

  • 后台:企业内部支撑的管理平台,是企业管理核心能力的系统。比如像企业ERP管理平台、企业财务管理平台等系统。

前台是对接用户的,所以系统需要快速响应前端用户的需求,快速创新、快速迭代。简而说来:快速建设、错了就推翻重来、不能耗费太大成本。

后台是企业对内的,为了支撑前台越来越多的业务,后台不断地建设,系统不断庞大地起来。所以后台系统需要扎实稳定,建成之后往往不能随意改动。简而言之,是需要耗费大力成本建设的基础能力、不能轻易推翻、改动成本极大。

前台和后台的矛盾,对“用户响应力”造成了巨大影响,用户满意度降低,企业的竞争力也逐渐丧失。

业务问题造成了技术层面的问题,开发工程师天天和产品打架、没日没夜赶需求,回头一想我再抽象一层不就得了。软件开发中遇到的所有问题,都可以通过增加⼀层抽象⽽得以解决!中台由此而诞生。

image-20200424144326465

中台就像是在前台与后台之间添加的⼀组“变速⻮轮”,将前台与后台的速率进行匹配,是前台与后台的桥梁。它为前台而生,易于前台使用,将后台资源顺滑流向用户,响应用户。

2.需要一个中台吗?

既然中台很重要,那是不是所有企业都要上一个中台呢,最近中台失败的案例不绝于耳,各种乙方败走,甲方责任人离职,甚至“阿里”的中台也随着几位负责人的调岗和离职,被质疑其是不是“凉了”(当然我认为阿里自身中台很成功)。所以有了一个新的问题:

“如果中台是一个解决方案,那么它要解决的问题是什么?”

中台的出现是为了提升企业IT能力的复用率;打通数据壁垒;为什么阿里构建的中台取得了成功成为了行业标杆,而在很多传统企业构建中台的规划和建设过程中,总是会遇到这样或那样的问题?阿里和这些企业有什么不同?

参考Thoughtworks,从中台构建的本质和原则谈起,他们认为有三个很棒原则:

<1>Strategic Initiative Over Tactic Initiative 战略举措胜于战术举措

image-20200424151313491

首先,当企业在构建自己中台之前,先要确定自己的中台转型能否达到战略举措的高度。所谓战略举措,意味着企业内部(包含业务和技术)一致认为要解决三个典型问题:提升IT能力复用率、打通数据壁垒、提升应用TTM;当中的一个或者几个。

战略目标要有阶段性的定义和检查。在2015年阿里做出的中台战略转型,也同样是一次大刀阔斧的战略转型。这样的转型意味着对于整个企业来说新的组织结构、新的合作方式、新的角色与职责边界的确立。同样,在阿里的案例当中,在聚划算出现之前,由于缺少组织的战略方向引领的时候,“共享业务事业部”的价值和地位同样非常尴尬:构建出来的服务没人用,而前台业务团队所提出的差异化需求都需要在中台承载,导致中台部门工作强度和压力都非常巨大。

在过去的十几二十年当中,很多业界企业的IT部门都曾经做过的“中台化”化或者“平台化”转型,但如果这一转型过程没有得到组织的战略的支持,没有拉通业务和技术的公司级的决策过程,那么转型就很难将转型拉到战略的高度,很多情况下,即使一个中台或者平台被构建出来,最终都在业务部门的层层压力之下,变得形同虚设,

<2>Business Decision Over Technical Decision 业务决策胜于技术决策

image-20200424151957032

还是看阿里,阿里中台的前身:共享业务事业部,是一个业务部门。阿里和许多传统企业不同,作为一家互联网公司,其最大的特点是“技术即业务”。技术和业务作为有机的整体,技术架构的重构的实质是业务本身的重构。

对于传统企业的分类法来说,最简单的就是把一个组织分为“业务团队”和“技术团队”两个部分。业务团队和IT团队是有着清晰的边界和合作模式的。而如果谈战略转型的话,这些企业业务的战略转型,和IT的战略转型可以是异步的,甚至完全不是一件事。要不要建中台、中台的构建原则以及基本交付形态,应当是一个业务决策而并非一个技术决策,业务先行是中台发展的关键前提。

对于技术含量更为集中的数据中台和算法中台,虽然目前并没有受到到业务过多的约束,但可以预见当IT构建的数据中台缺少领域专家和数据科学家的参与,同样难以在长期给企业的业务带来价值。由于要提供具有前瞻性的业务洞见,中台对业务领域专家和数据科学家的要求会变得更高而不是更低。如果数据中台的建设是业务决策而不是技术决策,业务的洞见和诉求会在第一时间融入到中台的建设过程中来,中台的价值风险也会相应降低。

<3>Empowerment Over Governance 赋能胜于治理

image-20200424152824020

自从企业构建了IT部门和团队,IT作为企业的成本中心,治理一直都是核心的职责和组织目标。治理的目标总体上是为了控制IT投入成本、提升IT构建效率,进而目标可以衍生出“降低成本、提升复用率、提升IT流程的标准化程度”等多种形态。控制成本和提升业务响应力是站在同一个天平两端的完全不同的需求。10年前,企业在苦苦思考敏捷转型能为自己降低多少IT研发成本;5年前,企业也在思考微服务架构的引入可以为自己降低多少IT投入。慢慢的,企业终于醒悟到,敏捷和微服务都是在为高响应力,而不是在为低成本服务。之所以中台在国内大火,某种意义上是因为国内企业的IT团队仍然在为自己的“成本中心”的定位寻找新的价值点。

我们再来观察阿里这种“技术即业务”的组织——治理其实仅仅是一种表象。通过业务主流程的标准化和中台化,前台的新业务会更快速地被构建出来,而不再需要新业务团队从头到尾完整地构建一遍其他业务部门已经构建过的业务。这时,治理的目标基本上已经完全退让给了赋能这一更大的目标。

跟着前面的思路,如果企业构建自己的平台或者中台,是作为一种战略出发的,并且是由业务团队主导的构建过程,那么这样的中台所要承载的使命,也必然远远大于一个“成本中心”所负担的使命。淡化治理、强化赋能的思路,可以使得企业在构建中台的过程中,更多的关注这一战略举措所带来的业务收益,而不会仅仅的关注到降低了多少IT成本;更多地关注野心勃勃的应用团队面向客户的需求来构建新的业务特性,而不是仅仅关注到团队使用了多少中台标准化的能力。

所以综上:在一个还没有实现“技术即业务”的企业当中,构建中台是一个需要通过企业战略引领、业务部门拉动、以构建生态为主要愿景的IT架构建设过程。如果这样的前提条件暂时不能满足,IT部门与其投资来构建一个颇具业务争议性的中台,不如回归到平台的本质——通过平台技术来打通交付瓶颈、构建开发者社区和生态、提供数据自服务平台以赋能业务自主挖掘洞见、通过构建实验平台来加速企业规模化创新的脚步、以及构建企业级用户触点平台以提供统一的用户交互体验。

“技术即业务”,这五个字是我理解中台的第二步。

0x02WHAT

1.中台的定义

中台,企业级能力复用平台。

我听过很多定义,但是当我顿悟后,发现这个定义虽然简单,但是准确。这九个字是我理解中台的第三步。

<1>企业级

企业级,定义了中台的范围,中台一定是企业级的。我们建设中台的目标是为了前台,一定要跳出单一的业务线,站在整个企业的视角去审视业务全,寻找可复用的能力进行沉淀。虽然中台的建设过程虽然可以自下而上,以点及面。但驱动力一定是自上而下的,从全局视角出发的,并且需要一定的顶层设计。这一点也引出了中台建设的一个关键难点,就是组织架构的调整和演进以及利益的重新分配是技术所不能解决的,也是中台建设的最强阻力。

<2>能力

企业的能力可能包含多个维度,常见的例如计算能力,技术能力,业务能力,数据能力,AI能力,运营能力,研发能力……其中大部分的能力还可以继续细化和二次展开,从而形成一张多维度的企业能力网。可以说,中台就是企业所有可以被「多前台产品团队」复用能力的载体。

<3>复用

复用,中台的核心价值。可复用性和易复用性是衡量中台建设好坏的重要指标,为了实现复用,需要将更高抽象(例如业务模式级别)的通用业务逻辑通过抽象后下沉到中台,这样前台就会更轻,学习成本和开发维护成本更低,越能更快的适应业务变化;缺点是,抽象级别越高,越难被复用,需要架构师和领域专家对业务有深入的理解和非常强的抽象能力。

<4>平台

平台,中台的形式。区别于大型单体应用或系统,传统的企业数字化规划更多的是围绕业务架构、应用架构和数据架构展开。但常出现的问题,一个是大单体系统的业务响应力有限,缺少柔性,当业务发展到一定阶段后,必然产生大量定制化需求,随着内部定制化模块的比例逐渐上升,响应力成指数下降,成为业务的瓶颈点。另一个则是系统间的打通通常比较困难,容易形成业务孤岛和数据孤岛。所以需要以平台化的方式重塑企业IT架构,从而给业务提供足够的柔性,来满足对于业务的快速响应和复用的需求。

企业级能力复用平台,这九个字是我理解中台的第三步。

2.中台什么样

<1>业务数据双中台

提起中台,绕不开也是最先想到的应该都是阿里巴巴的数据业务双中台。毕竟阿里的“大中台小前台”战略人尽皆知,其威力也是显而易见的。

image-20200424230240326

从图中可见,阿里中台主要体现为由业务中台和数字中台并肩构成的双中台,并肩扛起了所有前台业务。

  • 业务中台将后台资源进行抽象包装整合,转化为前台友好的可重用共享的核心能力,实现了后端业务资源到前台易用能力的转化。
  • 数据中台从后台及业务中台将数据流入,完成海量数据的存储、计算、产品化包装过程,构成企业的核心数据能力,为前台基于数据的定制化创新和业务中台基于数据反馈的持续演进提供了强大支撑。
  • 业务中台与数据中台相辅相成、互相支撑,一起构建起了战场强大的后方炮火群和雷达阵。

<2>技术中台

大中台小前台,并不代表前台不重要,相反,大中台的建设就是为了更好地服务好小前台,大中台的威力也需要靠小前台的引导才能真正发挥和体现出来。那如何快速构建出短小精悍,武器精良,战斗力十足的特种兵前台应用,充分发挥和释放出中台炮火群的威力,就需要依靠这里提到的技术中台。

image-20200424230752539

技术中台就是将使用云或其他基础设施的能力以及应用各种技术中间件的能力进行整合和包装。过滤掉技术细节,提供简单一致、易于使用的应用技术基础设施的能力接口,助力前台和业务中台数据中台的快速建设。

<3>研发中台

image-20200424231238999

软件开发是一项工程,涉及到管理、流程、测试、团队协作等方面。如何将企业的开发流程最佳实践沉淀成可重用的“能力”,从而助力创新性应用的快速开发迭代,也是我们看到的很多企业正在做的事情,我们可以管这种关注与开发效能管理的平台叫做研发中台。

如果说技术中台为前台应用提供了基础设施重用的能力,那研发中台就为前台应用提供了流程和质量管控以及持续交付的能力。

<4>组织中台

围绕技术展开并不是基于在中台构建中技术的重要性,而是因为技术的改进相对简单。而中台建设真正困难的是组织上的重构,这往往是大家有意无意避而不谈的。这里不得不说康威定律了:

Conway’s law: Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. - Melvin Conway(1967)
设计系统的组织其产生的设计等价于组织间的沟通结构。

中台建设真正困难的是组织上的重构,这往往是大家有意无意避而不谈的。中台战略的成功、能否实现技术架构与组织架构的匹配,是一道绕不过去必须要迈过的门槛。

为了真正解决企业创新在组织层面的摩擦和阻力,构建真正的平台型组织。《释放潜能-平台型组织的进化路线图》提出了上图这样一个平台型组织的组织结构。

image-20200424232310867

组织中台很像企业中的内部风投和创新孵化机构,为前台组织和团队构建创新型前台应用提供类似于投资评估、投资管理、投后管理,真正从组织和制度上支撑前台组织和应用的快速迭代规模化创新。

一切以”以用户为中心的持续规模化创新”为目的,将后台各式各样的资源转化为前台易于使用的能力,帮助我们打赢这场以用户为中心的战争的平台,我们都可以称之为中台:

  • 业务中台提供重用服务,例如用户中心,订单中心之类的开箱即用可重用能力,为战场提供了强大的后台炮火支援能力,随叫随到,威力强大;
  • 数据中台提供了数据分析能力,帮助我们从数据中学习改进,调整方向,为战场提供了强大及时的雷达监测能力,帮助我们掌控战场;
  • 技术中台提供了自建系统部分的技术支撑能力,帮助我们解决了基础设施,分布式数据库等底层技术问题,为前台特种兵提供了精良的武器装备;
  • 研发中台提供了自建系统部分的管理和技术实践支撑能力,帮助我们快速搭建项目,管理进度,测试,持续集成,持续交付,是前台特种兵的训练基地及快速送达战场的机动运输部队;
  • 组织中台为我们的项目提供投资管理,风险管理,资源调度等,是战场的指挥部,战争的大脑,指挥前线,调度后方。

其实还有很多中台,比如滴滴有出行中台,阿里巴巴还有移动中台以及各类算法中台、搜索中台等等。评判一个平台是否称得上中台,最终评判标准不是技术也不是长什么模样,最终还是得前台说了算,毕竟前台才是战争的关键,才是感受得到战场的残酷,看得见用户的那部分人。

0x03HOW

How并不是告诉大家怎么做,那会是一个更大的故事,而是我在理解中台的路上遇到的在关于how的一些词,他们困惑过我,但当我理解他们的时候,知道他们的差别的时候,会豁然开朗

1.中台战略

“战略”可能说起来都是比较大,听起来很虚的东西,但中台建设如前文建设原则所述,没有战略高度,最后就会形同虚设。中台这个概念,随着市场的炒作,越来越像一个个“许愿池”,承载了每家企业对于自己未来发展的美好愿景。但理想总是很丰满,而现实总是很骨感,世间一直没有“银弹”。

<1>中台建设过程中的问题

当我们开始建设中台时,一系列的问题就出现了:

image-20200425094713843

中台的建设既然是“企业级”,必然会涉及到组织的调整,甚至是组织的重新划分以及利益的重新分配,而这些都早已超出了技术能解决的范畴。一直是想方设法绕过组织这座大山,回归到熟悉的技术领域,尝试用技术的方式去解决碰到的所有问题,但神奇的是组织的大山总会在中台建设的某个关键阶段,像海市蜃楼一样突然出现在面前,阻挡在前进的路上,绕也绕不开。组织可能不是中台建设的阻碍,而恰恰是中台建设的本质。这不正是“康威定律”的另一种表述。

<2>中台建设需要关注组织架构

回答这个问题可以从两个方向推演:一个是自上而下,一个是自下而上。

  • 自上而下:组织重构是战略落地的必经之路

而战略的落地,往往就是靠组织的调整来实现的。美国的管理大师钱德勒就表达过组织结构从属于战略的观点,即“企业的发展取决于两个变量,一个变量是企业正确的战略,另一个变量,就是企业的组织结构。这两个变量之间,前者决定后者,后者保证前者的落地实现。”马云也曾在湖畔大学的分享《使命、愿景、价值观、组织、人才、KPI》中提到过:“战略最后的本事不是你设计了多好一个Plan,而是你落实到了什么样的组织,谁来干,考核指标是什么?”

img

可见中台战略之所以是企业级的数字化战略转型的一部分,从战略落地的角度来看,组织调整是其中重要的一环,也是战略真正落地的重要体现。

  • 自下而上:组织是中台建设荆棘道路上的一道坎

实际去观察,目前很多企业的中台建设,仍然主要是以技术驱动为主,以IT治理为目标,天天谈论的还大多是微服务怎么拆、技术架构如何选型此类的问题。不是说这些问题不重要,而是技术驱动的一个主要问题在于:很难讲清楚中台建设对于业务的价值。而讲不清楚中台建设对于业务的价值,就得不到相应的资源,这里的资源主要就是钱和人。

没有资源的支持,技术团队就只能自己委屈点儿,吃苦耐劳,加班加点,用有限的资源既要满足业务上的需求,又要借着这个机会做中台的改造,甚至是闷着头偷着做的,卧薪尝胆。但结果却往往并不好,好不容易硬着头皮加班加点赶完了一个版本,上线了,需要前台应用接入了,这时问题才暴露出来,例如经常出现这样的声音:

  • 我们(其他团队)为什么要用你的中台,我们也建了一个,要不你用我的吧……
  • 我们(其他团队)为什么要把数据给你?我这儿也有一个数据中台,你能不能把你的数据先给我一份儿……

为什么中台建设必然会在某个阶段遇到组织这个无法逾越的坎,所以如果不在一开始考虑清楚,必然会让自己在中台建设的某个阶段处于一个进退两难的境地,非常被动。

<3>问题的本质到底是什么?

问题不在于企业原本是哪类的组织结构,问题在于中台团队本身的定位。中台团队被定位成一个共享职能团队,中台团队与前台团队之间的关系是服务和被服务的关系,这才是问题的关键。

因为中台是一个共享服务团队,与前台是服务与被服务的关系。那自然前台出钱,中台团队为其提供服务就是天经地义的事情,正所谓“拿人钱财替人消灾”。这时候就会出现两种情况:因为中台建设的复杂性和长期性,导致短期无法满足前台团队的短期业务需求,业务方不满,觉得花了钱没有得到相应的服务;中台团队责因为背负着业务的持续施压,无法按照自己的节奏推进中台建设,痛苦不堪,矛盾产生。短期战术目标与长期战略目标的矛盾。一种情况是,中台团队迫于压力极力满足前台的需求。但因为中台的企业级性质,中台团队需要同时面对多个不同的前台业务、前台团队。因为每一个前台团队都是“金主、客户、甲方”,在中台团队眼中地位是一样的,都是需要极力满足需求的。而因为前台团队“花了钱”,为了能获取更多的中台资源使用权,自然都会给中台团队提出各种各样的需求,来争取到更多的中台资源,导致中台团队的需求短时间剧增,但因为毕竟中台的资源有限,所以自然而然会出现之前反复提到的需求剧增、排期、冲突等问题,矛盾产生。多前台由于中台资源竞争所产生的矛盾。

<4>Platform as a Product!

那问题如何破?给中台一个边界,产品的边界,将中台团队从共享职能团队转变为中台产品团队,将前台与中台的关系由被服务与服务的关系变为产品与产品的关系 ,即:

Platform as a Product!

如果中台是一个产品,则意味着:

  • 中台作为产品需要有自己的愿景定位,不一定需要满足所有前台客户的需求,这同样也意味着前台可以选择不使用中台的某些能力而选择自建。

  • 中台作为产品需要有自己清晰的用户定位和用户划分,前台作为中台的用户不再是平等的,VIP前台用户的需求要优于免费前台用户的诉求,通过产品上常见的用户划分来解决需求膨胀、排期、优先级和冲突问题。

  • 中台作为一个产品,需要想方设法体现自身的价值,真正为前台客户解决实际问题,并关注前台用户体验,通过营销和售前等手段获取前台客户,通过清晰的用户定位和产品力吸引前台客户,让其主动选择采购中台产品。

  • 产品的建设初期,不一定启动资金直接从业务上切分,可能需要类似于天使投资的企业战略投资进行初始孵化,减少中台前期建设的业务交付压力,甚至作为企业的战略级产品,需要一些内部保护和孵化,但仍需要快速验证其价值,获取客户,实现自负盈亏。

其实阿里巴巴早已将自身的中台能力,通过产品化包装整合到了阿里云上,对外输出,无论是承载了技术中台能力的Aliware,还是承载着数据中台能力的Dataphin,还是承载着研发效能能力的云效。

基于企业的使命与愿景,结合当前的商业形势,制定匹配的公司战略,并基于战略迅速调整组织进行战略落地。 再根据康威定律,通过组织的变化引导IT架构的演进,所以中台的诞生只是企业战略层面上,在企业发展某个阶段强调加强组织横向协同性的一个中间产物而已。

2.业务中台

当我们在聊业务中台,我们总是提到,微服务、DDD、Event Storming,我们在讨论各种业务中台的共性能力识别和微服务划分的时候,总是能看到DDD、Event Storming这两位的身影。那他们到底和中台什么关系呢?我们先从DDD说起。

<1>DDD(领域驱动设计)

Domain-Driven Design第一版本是03年发布的,DDD虽然诞生的早,但直到现在,和我们日常工作的距离也并不远,例如我们代码中经常出现的XxxEntity,XxxRepository ,XxxService,XxxFactory……这些类,这里的Entity、Repository、Service和Factory,以及我们现在大家早已习以为常的分层架构,都是出自DDD之手,只不过很多人已经不知道这些都是拜DDD所赐而已。

DDD其实就是面向对象的一套“方言”,提供了一种基于业务领域的对象划分和分类方法,其最大的价值就在于对于软件开发过程全生命周期使用语言的统一!

在面向对象的世界,只告诉了我们万事万物皆是对象。但并没有告诉我们对象究竟应该怎么组织,该以什么角度进行划分。而作为技术人员的我们,早已习惯了从技术的角度出发思考,自然就出现了“用技术的语言”定义对象的习惯,例如最常见的DAO(Data Access Objects),DTO(Data Transfer Object)这类对象的划分方式就是使用技术视角看待和分类对象的典型案例。这样从技术视角分类对象的问题,就在于在软件的开发过程中,会涉及到多“语言”间的对应和翻译,例如最常见的就是业务语言和技术语言的相互翻译。想想周围经常出现的研发和产品之间各种痛苦的沟(吵)通(架)场景。而DDD的出现,就是为了解决这个问题。它通过一套面向对象的分类方法或是方言体系,从领域出发,实现软件开发过程中各个角色和环境的“统一语言”(UBIQUITOUS LANGUAGE)。

了解了DDD的来历和价值,那我们还有疑问,既然DDD这个概念已经快被人们淡忘了10多年了(虽然我们一直还在不知不觉中僵硬地应用着),那为什么最近一两年又突然重出江湖,重新被大家关注了呢?答案其实就两个:微服务和中台。

其实DDD一开始的时候,就把领域分析设计分为了战略和战术两个部分。按道理应该从战略入手,再下沉到战术部分。但是Eric Evans在写《Domain-Driven Design》这本书时,可能是基于当时的环境,却是先写的战术部分,书的后半部分才开始展开DDD的战略部分。

image-20200425151806052

直到微服务的横空出世……随着微服务架构的兴起,微服务到底如何拆分就成了人们最最关注的问题。这时候一些“老人儿”们突然想起来,这不是正是应用DDD中战略部分(问题域,限界上下文)应用和施展拳脚的场合么?!所以随着微服务的爆炸式发展,DDD这位退隐已久的老江湖,又再次被请出了山,站到了大家的面前。而此时,他身边还多了一个年轻的新搭档,他正是:事件风暴。

<2>EventStorming(事件风暴)

现在,当很多人谈到DDD都会同时谈到EventStorming,甚至有人误认为这两个名词本身指代的就是同一个概念。但其实这是两个完全独立的工具。DDD是一套基于领域的分析和建模方法,而EventStorming则是一套Workshop方法。

img

上图是EventStorming的一个概括,从图中,我们可以看出阐释了从系统外部与用户的交互,到系统内(事件-策略-命令-聚合-事件)的事件传递涟漪,以及通过事件影响到读模型从而给予用户动作的响应,从而形成完整闭环的全过程。对我们了解还原系统的全貌非常有帮助。

DDD提供了一套面向对象的“方言”,给出了一套面向对象的分类框架和架构指引,但是在DDD中并没有明确给出如何为一个系统识别出这些不同种类的对象的过程和方法。而EventStorming的出现正好弥补了这个空白,通过EventStorming工作坊的方式,正好给我们提供了一个还原和分析系统的方法,并最终通过“聚合”这条红线,穿越时空,无缝切入到DDD的领域范畴之内,以“聚合”为支点,向上可以进一步做问题域和限界上下文的战略分析,向下则可以通过聚合的进一步展开进行实体、值对象等相关的战术分析,引导落地。而DDD战略设计中问题域和限界上下文的识别,则为我们划分微服务提供了非常强有力的支撑,至此我们就通过EventStorming和DDD的这一对强力组合的联袂辅助下,找到了解决了微服务架构下最困难问题之一的,既服务该如何划分问题的解题思路和落地方法。

<3>DDD、EventStorming与业务中台

业务中台解决的是企业级能力复用的问题,而微服务解决的是运行时解耦的问题。业务中台不一定是微服务的,采用微服务架构的也不一定就是业务中台。所以很多人以为使用DDD和EventStorming规划业务中台,是因为微服务,基于以上的分析这也是站不住脚的,难道我不用微服务架构来实现业务中台,就无法使用DDD和EventStorming了么?DDD和EventStorming的结合,形成的是一套“领域分析方法”,可以想象成一套双剑合璧的剑阵。其目的是透过现象看本质,透过表面的业务流程来分析背后的核心领域问题和概念,而微服务架构只是使用了这套能力,来指导和帮助进行服务划分而已,并且也不是唯一的指导原则,其他还需要考虑像团队组成、变更频率、技术异构边界、SLA要求等等因素……

而对于业务中台,这套领域分析方法,则可以指导我们探究与分析业务中台规划过程中的一个最困难的问题,既:识别不同的业务线,到底有哪些业务是可以复用的?而这种通过领域分析和抽象,找寻不同业务线背后面对的相同的问题域,并从中提取共性的业务模型、提取共性的业务功能、提取共性的业务流程、甚至是提取共性的业务模式,加工并予以复用的过程,也正是业务中台的规划与建设过程的关键所在。

img

3.数据中台

当我们聊数据中台的时候,总是听到数据仓库、3NF、维度建模、数据湖、数据治理、人工智能,我们先从维度建模开始。

<1>数仓建模

数仓建模的方法都是老面孔,他们设置在我出生之前就已应用数仓建模方法论有很多3NF、Inmon 模型以及kimball的维度建模。

学过数据库的都知道范式:

  • [第一范式](1NF)无重复的列。

  • [第二范式](2NF)非主属性非部分依赖于主关键字。

  • [第三范式](3NF)属性不依赖于其它非主属性。

img

OLTP系统数据(可以笼统为业务后端用的数据)的主要用的建模方式就是三范式,从而在事务处理中解决数据的冗余和一致性问题。Inmon就是数仓之父,他提出的建模方法是从全企业的高度设计一个3NF模型,但是数仓的3NF和OLTP中的3NF的区别在于,它是站在企业的角度面向主题的抽象,而不针对具体业务过程。他推崇自上而下的建模方式,即从数据源到数据仓库再到数据集市的(先有数据仓库再有数据市场)一种瀑布流开发方法。建模主要步骤:

  1. 高层模型:一个高度抽象的模型,描述主要的主题以及主题间的关系,用于描述企业的业务总体概况;
  2. 中层模型:在高层模型的基础上,细化主题的数据项;
  3. 物理模型:在中层模型的基础上,考虑物理存储,同时基于性能和平台特点进行物理属性的设计,也可能做一些表的合并、分区的设计等。

Kimball 维度模型推崇自底向上的设计模式,即从数据集市到数据仓库再到数据源(先有数据集市再有数据仓库)的一种敏捷开发方法。Kimball都是以最终任务为导向。首先,在得到数据后需要先做数据的探索,尝试将数据按照目标先拆分出不同的表需求。其次,在明确数据依赖后将各个任务再通过ETL由Stage层转化到DM层。这里DM层数据则由若干个事实表和维度表组成。接着,在完成DM层的事实表维度表拆分后,数据集市一方面可以直接向BI环节输出数据了,另一方面可以先DW层输出数据,方便后续的多维分析。建模主要步骤:

  1. 选择业务过程,业务过程可能是交易的支付、下单等,也可能是当前用户余额等。

  2. 选择粒度,粒度是维度的组合,类比:国家粒度、城市粒度。

  3. 识别维表,通过选择的粒度从而设计好维表。

  4. 选择事实,确定分析需要的指标。

    img

    Inmon的核心企业数据仓库要求规范化表,需要大量的时间来梳理和设计数据表结构,但如果规范化数据仓库一旦建立好了,则以后数据就更易于管理。而且由于开发人员不能直接使用其中心数据库,更加确保了数据质量,中心数据库是采用规范化设计的,冗余情况也会更少。而维度建模数据仓库对数据表结构没有强规范型要求,数据仓库建设敏捷性就更好点,而且适用于业务变化比较频繁的情况,对开发人员的要求也没有规范化数据仓库那么高。我们在实际的数仓开发中往往针对不同的数据场景平衡两种方法论结合使用。

<2>数据湖、数据平台、数据仓库/BI

实际上它们之间根本不在一个维度上。数据中台是个概念,而数据仓库是一种具体的技术领域,它也已经有对应的标准化的产品。商业智能一方面也是一个概念,另一方面它也有对应的产品。

传统的商业智能和数据仓库,是以分析报表为核心。把数据加工成分析报表,提供给决策层去看的。这样的辅助决策系统,叫商业智能,它的底层是数据仓库,因为它要跨域存储和处理加工企业的历史数据。数据平台是企业有了大数据的情况下,希望能够采集全量的数据,包括采集非结构化数据的大数据平台。数据仓库、数据平台都是技术类系统,不能直接服务于业务。而数据中台,企业希望它能直接服务与业务前台。商业智能主要的用户是决策层,它主要提供服务的方法是分析报表、数据湖和数据平台。它的主要的使用对象实际上是数据开发者、数据技术人员和数据分析师。

数据中台的用户则是企业所有的数据用户,数据消费者,还包括业务系统。数据中台是能直接服务于业务的平台。它能离具体业务更近,以多种方式为业务、系统提供数据产品。

image-20200425224714951

如果从出发点来说,现在的技术选型、技术工具是很多的,但是最重要的是我们对一件事情的概念上的认知,只要目标和认知清晰了,那么实现它的办法是有很多种的。数据中台和数据平台最大的区别是什么?我们认为数据中台是离业务更近。业务需要什么服务?是数据中台和数据服务。中台的部门或者团队,最优先考虑的是提供给业务所需要的服务。但数据平台不一样,数据平台最核心的是数据的存储、加工。

数据中台是为企业所有的数据消费者提供数据服务/产品的平台。

0x04写在最后

在企业数字化道路上,战略、业务、IT的边界会慢慢消失,所有的战略、业务都需要技术的支撑。企业需要成为一个灵活的胖子,而不是行动迟缓的巨人。中台涉及的面很广,虽然写本文的时候,是先有why再有what再how,但实际中,我确是先对how有了解,从how发现很多事情在技术层面是说不通的,才会追根溯源,尝试刨根问底,终于初窥门径。

一份复习数学的书单[0]--For The ML

发表于 2018-09-02 | 分类于 读书 , 数学

0x00 开始

其实从很早就接触ML,大学时期做的一个比赛会用一些决策树和Q-learning的东西,不过现在回忆起来,当时简直是盲人摸象都算不上。之前给客户做数据时,会有些数据挖掘的需求,也自己看了数据挖掘和ML的一些书,但书中很多公式一知半解,一本书看到一半时基本没法看下去了,然后下定决心对ML相关数学进行重新复习。摸索一段时间后,找了一些好的书和资料,有一些收获,在此整理归纳。

0x01 书单

1. 课本(套书)

课本

高等数学(上) https://book.douban.com/subject/2112359/
高等数学(下) https://book.douban.com/subject/2195654/
线性代数 https://book.douban.com/subject/2197140/
概率论及数理统计 https://book.douban.com/subject/3165271/

其实课本大家的评价都不是太高,无非三点导致了困难:
[1] 中国作者大都上来说的比较难,让初学者比较懵,作者有时很难从一个初学者的角度去著书;
[2] 对于我学习CS学科,开始学高数时,不知道学这些东西对我的学科学习有什么帮助,书中也没有相应的引导;
[3] 缺少趣味性,中国太强调学习的困难性,这种思维习惯会带到课本中来,从而没有展现数学最有趣的那一面。
从现在看三本课本读来并非全无益处,毕竟是同济和浙大两个985学校老师出的,知识的体系性和完整性还是较好的。作为练习册还是很好的。

这里另外提一个概率论与数理统计的课本,笔者并未读过,但评价很高,可以替代浙大的版本。是USTC陈希孺老师写的概率论与数理统计,可以替换浙大的版本去读。

概率论与数理统计 概率论与数理统计

1536126191909

2. 程序员的数学(套书)

这套书共三册,一套日本人写书,日本人写的技术书都很容易上手,开始的时候简单到你在怀疑书的标题。这套书并不是按照 微积分、线性代数、概率论的顺序,三本书两个作者,第一本是结城浩,一个程序员,后两本的作者是平冈和幸和堀玄,都是工程学博士。

程序员的数学一

程序员的数学 https://book.douban.com/subject/19949020/
第一册说的更多的是一些程序中的数学思维方式,很入门很基础,性价比并不是很高,读起来耗时并不会太长。

但是,对!这里是有”但是”的,结城浩的这本书写的太简单了,但你绝不能低估作者,结城浩绝对是写数学书的好手,因为他有一套笔者觉得很牛逼的书。封面是这样的:

1536126595919

数学女孩!对!你没看错,这套书的名字分别是:数±学=女×孩(其实这本是微积分的内容),数±学=女×孩(2)-费马大定理,数±学=女×孩(2)-哥德尔猜想。笔者读第一本书时,觉得是一本披着数学外衣的纯情小说,看了半册后发现这是一本披着纯情故事的数学书!!!不过此套书很有趣,读起来太有意思了,以后细述。作者准备写六册,拭目以待。

1536127204330

程序员的数学2 https://book.douban.com/subject/26593822/

第二册是概率统计,作者从提供了独特的上帝视角,从面积和体积去理解概率问题,很适合入门和复习概率论。

程序员的数学3

程序员的数学3 https://book.douban.com/subject/26740548/
第三册是线性代数,此书作者用了很多图让读者理解矩阵的变换作用,为了应书名,书中对计算机计算矩阵相关的数值算法进行了详解,很适合程序员复习线性代数。

3. 普林斯顿微积分读本

1536128524102

普林斯顿微积分读本 https://book.douban.com/subject/4926707/

这本书确实是普林斯顿的一个数学博士写的,虽说这本书名字很夸张,有点让普林斯顿背书的感觉。此书基本从高中起点开始说起,本身应该是给普林斯顿学生入门用的,从函数说到微分方程。此书算技术书里翻译质量的上乘,很多大龄程序员也在靠这本书复习微积分,进入ML。笔者阅读半本,觉得如故事书一般,作者是娓娓道来,同时伴有很多实际中的应用场景,满足读者对应用的好奇心。

4. 线性代数的几何意义

线性代数的几何意义

这本书是中文里最好的线性代数书,没有之一!读这本书,从头读,如读小说一般,引人入胜,后半部越来越精彩,读着的时候,心里都在鼓掌,精彩精彩。如果阅读别的线性代数书有困难,请读此书! 极力推荐!此书可再配合3Blue1Brown的视频一起观看理解。嗯,这套视频是说线性代数最好的视频,没有之一!!

线性代数的本质 https://space.bilibili.com/88461692/#/channel/detail?cid=9450 (没有看错,要在B站学数学)

5. 线性代数应该这样学

线性代数应该这样学

线性代数应该这样学 https://book.douban.com/subject/3715623/

此书,大学时就读了一些,说实话当时觉得太抽象(可能也是没认真读),就放弃了。现在读起来,作者提供了从线性映射和算子的角度学习线性代数,加深对线性代数的认识。

6. Introduction to Linear Algebra

线性代数

Introduction to Linear Algebra https://book.douban.com/subject/26824921/

这本书其实并未细读,这本书是MIT线性代数的课本,上大学的时候看视频知道此书的,老爷子Gilbert Strang说课很有趣,他还有一门复习微积分的公开课也很棒。现在看来大家对此书评价很高,准备作为线性代数体系性的整理读物。

7. 行为科学统计概要

1536130861056

行为科学统计概要 https://book.douban.com/subject/4268015/
统计学入门书,通俗易懂,结合了很多实例来展示统计的作用。

9. 练习

1536131141659

恕笔者比较愚钝,觉得数学如果学了不练习等于白学,所以需要一定的练习量去配合读书,巩固阅读效果。说到做题,我大中华说做题第二,没有哪国敢说是第一的。所以笔者买了当年考研的复习书作为练习册检验学习成果。

0x02 读书顺序

课本是数年前在学校读的,此次复习时开始读的是课本的概率论及数理统计,中间遇到微积分,开始阅读普林斯顿微积分读本复习微积分。同时开始阅读程序员的数学,程序员数学1简单可速读,读23前,读线性代数的几何意义,然后读23以及读本完成线性代数和概率论的复习。然后阅读线性代数应该这样学,行为科学统计概要前半部分简单可速读,后部分慢读。中间配以习题练习,以及夹读ML相关书目作为关联应用。

如果有同样在为了ML复习数学的同仁,可加笔者微信一起交流:

1536132698055

爬取3000个城市与地区8年天气数据

发表于 2018-08-06 | 分类于 python , 爬虫

0x00 为什么采集天气数据

一日走在路上,在想关于销售预测的相关,发现很多预测状况都与天气有巨大的关联,最近也正好在看爬虫相关的,搜索了一番,发现网上有按月展示的数据,但无数据包,所以开始了自己爬取数据的过程。由于网站提供的数据很好采集,也无限制,所以采集的很顺利,总共采集了大概800W条数据。

0x01分析页面

在城市列表页:http://lishi.tianqi.com/ 可通过每个城市名点击,进入单个城市的详情页:http://lishi.tianqi.com/beijing/index.html (以北京为例),在此页中存有北京市天气的详细数据列表:

1533542419290

点击后进入月天气详情页:http://lishi.tianqi.com/beijing/201806.html (北京市2018年6月天气详情页)

1533542558814

由此获取的目标数据就在城市的月份天气详情页中。

0x02 采集过程

  1. 从城市列表页获取每个城市URL;
  2. 利用每个城市URL通过组装生成城市月份URL;
  3. 爬取每个城市月份页中的天气数据;
  4. 每个城市一个文件存数据;

0x03 代码实现

1 . 获取城市列表

访问https://lishi.tianqi.com/,获得城市列表写入citylist.csv。

1
2
3
4
5
6
7
8
9
10
11
12
13
def getCitylist(self):
listurl = "https://lishi.tianqi.com/"
file = open('citylist.csv', 'w')
response = request.urlopen(listurl)
soup = BeautifulSoup(response, "html.parser")
citylist = soup.select('[class="bcity"]')
for cityinfoindex in citylist:
for cityinfo in cityinfoindex.select('a'):
str = ""
str += cityinfo.get('title')[:-4] + ',' + cityinfo.get('href')
if str.__contains__("http"):
file.write(str + '\n')
file.close()

2.城市月份天气页处理

访问城市月份天气页,通过BeautifulSoup提取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def cityDl(self,urllist,cityname):
filename = cityname + ".csv"
file = open(filename, 'w')
urls = urllist
for url in urls:
response = request.urlopen(url)
soup = BeautifulSoup(response, 'html.parser')
weather_list = soup.select('div[class="tqtongji2"]')
print(weather_list)
for weather in weather_list:
ul_list = weather.select('ul')
i = 0
for ul in ul_list:
li_list = ul.select('li')
str = ""
for li in li_list:
if li.string is not None:
str += li.string + ','
else:
str += ','
if i != 0:
file.write(str + '\n')
i += 1
file.close()

3. 控制函数

由于月份格式需两位,所以10月之前的月份需要补0,例如2018年6月需为:201806,所以单独写了一个函数生成月份列表。当然也尝试了python的库,发现实现很麻烦,所以自己实现了月份列表的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def monthList(self, beginDate, endDate):
mList = []
mList.append(beginDate)
begin = int(beginDate)
end = int(endDate)
beginY = int(beginDate[0:4])
beginM = int(beginDate[4:6])
while begin < end:
tdate = ""
if beginM == 12:
beginY += 1
beginM = 1
else:
beginM += 1
tdate += str(beginY)
if beginM < 10:
tdate += '0'+str(beginM)
else:
tdate += str(beginM)
mList.append(tdate)
begin = beginY*100+beginM
return mList

控制函数首先读取 getCitylist生成的citylist.csv,然后通过monthlist获得需要抓取的月份list,通过循环控制生成城市的天气urllist,然后调用cityDl抓取天气数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def taskControler(self):
citylist = list(csv.reader(open('citylist.csv', 'r')))
timelist = self.monthList("201101", "201806")
for i in citylist:
cityurl = i[1][:-10]
cityname = i[0]
print(cityurl,cityname)
urllist = []
for d in timelist:
turl = ""
turl = cityurl+str(d)+".html"
urllist.append(turl)
print(urllist)
self.cityDl(urllist, cityname)

0x03 关键点

整体来说这个网站的抓取很简单,笔者甚至认为算不上爬虫任务。在其中有两个关键点帮助笔者高效的完成了任务:

1. python的数组切片

python对数组的切片功能很强大,以数组:[0,1,2,3,4,5,6,7,8,9]举例

  1. 取第四至第六个元素:

    由于切片中用的range,所以需要4:7

    IN:

    1
    2
    a=[0,1,2,3,4,5,6,7,8,9]
    a[4:7]

    OUT:

    1
    [4, 5, 6]
  2. 取倒数第一个元素

    IN:

    1
    2
    a=[0,1,2,3,4,5,6,7,8,9]
    a[-1]

    OUT:

    1
    [9]
  3. 取后5个元素

    IN:

    1
    2
    a=[0,1,2,3,4,5,6,7,8,9]
    a[-5:]

    OUT:

    1
    [5, 6, 7, 8, 9]
  4. 取除去后5个元素的数组

    IN:

    1
    2
    a=[0,1,2,3,4,5,6,7,8,9]
    a[:-5]

    OUT:

    1
    [0, 1, 2, 3, 4]
  5. 每三个数取一个数

    IN:

    1
    2
    a=[0,1,2,3,4,5,6,7,8,9]
    a[::3]

    OUT:

    1
    [0, 3, 6, 9]

    python提供的切片真的很方便,当然还有很多骚手法等待大家挖掘,这里就不一一列举

2. Beautiful Soup

Beautiful Soup is a Python library for pulling data out of HTML and XML files. It works with your favorite parser to provide idiomatic ways of navigating, searching, and modifying the parse tree. It commonly saves programmers hours or days of work.

Beautiful Soup提供了一套十分好用的html解析器,可以不用直面正则表达式,并且可以使用很容易理解的代码完成页面解析、数据提取。以下是各种解析器的对比,具体使用可以参考官网。

1533610947301

在本例中,笔者使用了beautiful soup去城市月份天气页中过滤天气数据:

1
2
3
ul_list = weather.select('ul')
..............
li_list = ul.select('li')

0x04 效果

代码总共运行了有3天左右,中间由于错误和断网终端了几次,实际耗时更多。共采集了3180个城市的数据,300M大小。

1533611572212

0x05 可改进点

1.错误及异常处理

在运行过程中,多次因为网络原因和URL错误导致程序中断,可以通过添加异常处理进行跳过,并记录访问异常URL

2.多线程

单线程跑程序过慢,大部分时间消耗在等待HTTP响应上,其实可以通过多线程,并行任务。

不过python的多线程只会调用一个核。

Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。

后期有时间优化。

基于Pyecharts的数据可视化

发表于 2018-07-11 | 分类于 python , 数据可视化

0x00 python环境安装及配置

1. 关于python版本

关于python的版本讨论实在是太久远了,现在都2018年了,如果不是维护原来的代码版本,应该毫不犹豫的选择python3.x,python2和python3有很多不兼容,会造成麻烦。谁还会选择一个十年前的版本呢?而且越来越多的库是基于python3去构建。

选择Python3.x!!!

2. 关于python集成环境

笔者最早使用,使用官方安装包,但各种配置包管理是一件很头疼的事,特别是各种库、包的安装及处理他们的依赖关系,最后使用Anconda,完成的大部分包管理,并且提供了各类工具,对数据科学十分友好。

Anconda下载地址: https://www.anaconda.com/download/,安装傻瓜式,一路下一步。

3. Jupyter Notebook

Jupyter Notebook 的本质是一个 Web 应用程序,支持在浏览器中运行Python脚本,这样天然的支持pyechart在浏览器中实时展示,而不是通过程序生成html文件后,查看html文件才知道可视化结果。

0x01 pyechart安装及配置

Pyechart官网地址:http://pyecharts.org
默认情况下,pyechart并不在anconda的库list中,在pyechart的github网站(https://github.com/pyecharts/pyecharts)上提供了两种安装方式:

1 > 通过pip:

1
$ pip install pyecharts

2 > 从github clone 然后安装

1
2
3
4
$ git clone https://github.com/pyecharts/pyecharts.git
$ cd pyecharts
$ pip install -r requirements.txt
$ python setup.py install

经过笔者测试,强烈推荐使用第二种方式,第一种方式安装的版本可能是低于官方文档,并且很多新特性是无法使用的。

0x02 pyechart的使用

==使用中特别的要点:==

Pyechart使用的库是基于echart实现的,虽然pyechart包含了大部分重要参数,但很多参数是在pyechart中没有定义的,需要通过 **kwargs引用,具体的需要查看pyechart的源码详细了解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

def __init__(self, title="", subtitle="", **kwargs):
super(Liquid, self).__init__(title, subtitle, **kwargs)
self._js_dependencies.add("liquidfill")

def add(self, *args, **kwargs):
self.__add(*args, **kwargs)

def __add(
self,
name,
data,
shape="circle",
liquid_color=None,
is_liquid_animation=True,
is_liquid_outline_show=True,
**kwargs
):

。可以添加的参数在http://echarts.baidu.com/option.html#title中查看。

官方文档:http://pyecharts.org/#/
以下示例引用自官方

1. 柱状图

1
2
3
4
5
6
7
8
9
from pyecharts import Bar

attr = ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
v1 = [5, 20, 36, 10, 75, 90]
v2 = [10, 25, 8, 60, 20, 80]
bar = Bar("柱状图数据堆叠示例")
bar.add("商家A", attr, v1 )
bar.add("商家B", attr, v2)
bar

2. 3D柱状图

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
36
37
38
39
40
41
42
43
44
45
46
from pyecharts import Bar3D

bar3d = Bar3D("3D 柱状图示例", width=1200, height=600)
x_axis = [
"12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a",
"12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p"
]
y_axis = [
"Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"
]
data = [
[0, 0, 5], [0, 1, 1], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0],
[0, 6, 0], [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 2],
[0, 12, 4], [0, 13, 1], [0, 14, 1], [0, 15, 3], [0, 16, 4], [0, 17, 6],
[0, 18, 4], [0, 19, 4], [0, 20, 3], [0, 21, 3], [0, 22, 2], [0, 23, 5],
[1, 0, 7], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0], [1, 5, 0],
[1, 6, 0], [1, 7, 0], [1, 8, 0], [1, 9, 0], [1, 10, 5], [1, 11, 2],
[1, 12, 2], [1, 13, 6], [1, 14, 9], [1, 15, 11], [1, 16, 6], [1, 17, 7],
[1, 18, 8], [1, 19, 12], [1, 20, 5], [1, 21, 5], [1, 22, 7], [1, 23, 2],
[2, 0, 1], [2, 1, 1], [2, 2, 0], [2, 3, 0], [2, 4, 0], [2, 5, 0],
[2, 6, 0], [2, 7, 0], [2, 8, 0], [2, 9, 0], [2, 10, 3], [2, 11, 2],
[2, 12, 1], [2, 13, 9], [2, 14, 8], [2, 15, 10], [2, 16, 6], [2, 17, 5],
[2, 18, 5], [2, 19, 5], [2, 20, 7], [2, 21, 4], [2, 22, 2], [2, 23, 4],
[3, 0, 7], [3, 1, 3], [3, 2, 0], [3, 3, 0], [3, 4, 0], [3, 5, 0],
[3, 6, 0], [3, 7, 0], [3, 8, 1], [3, 9, 0], [3, 10, 5], [3, 11, 4],
[3, 12, 7], [3, 13, 14], [3, 14, 13], [3, 15, 12], [3, 16, 9], [3, 17, 5],
[3, 18, 5], [3, 19, 10], [3, 20, 6], [3, 21, 4], [3, 22, 4], [3, 23, 1],
[4, 0, 1], [4, 1, 3], [4, 2, 0], [4, 3, 0], [4, 4, 0], [4, 5, 1],
[4, 6, 0], [4, 7, 0], [4, 8, 0], [4, 9, 2], [4, 10, 4], [4, 11, 4],
[4, 12, 2], [4, 13, 4], [4, 14, 4], [4, 15, 14], [4, 16, 12], [4, 17, 1],
[4, 18, 8], [4, 19, 5], [4, 20, 3], [4, 21, 7], [4, 22, 3], [4, 23, 0],
[5, 0, 2], [5, 1, 1], [5, 2, 0], [5, 3, 3], [5, 4, 0], [5, 5, 0],
[5, 6, 0], [5, 7, 0], [5, 8, 2], [5, 9, 0], [5, 10, 4], [5, 11, 1],
[5, 12, 5], [5, 13, 10], [5, 14, 5], [5, 15, 7], [5, 16, 11], [5, 17, 6],
[5, 18, 0], [5, 19, 5], [5, 20, 3], [5, 21, 4], [5, 22, 2], [5, 23, 0],
[6, 0, 1], [6, 1, 0], [6, 2, 0], [6, 3, 0], [6, 4, 0], [6, 5, 0],
[6, 6, 0], [6, 7, 0], [6, 8, 0], [6, 9, 0], [6, 10, 1], [6, 11, 0],
[6, 12, 2], [6, 13, 1], [6, 14, 3], [6, 15, 4], [6, 16, 0], [6, 17, 0],
[6, 18, 0], [6, 19, 0], [6, 20, 1], [6, 21, 2], [6, 22, 2], [6, 23, 6]
]
range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
'#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
bar3d.add("", x_axis, y_axis, [[d[1], d[0], d[2]] for d in data],
is_visualmap=True, visual_range=[0, 20],
visual_range_color=range_color, grid3d_width=200, grid3d_depth=80)
bar3d

3. 仪表盘

1
2
3
4
5
from pyecharts import Gauge

gauge = Gauge("仪表盘示例")
gauge.add("业务指标", "完成率", 66.66)
gauge

4. 极坐标

1
2
3
4
5
6
7
8
9
10
11
from pyecharts import Polar

radius = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
polar = Polar("极坐标系-堆叠柱状图示例", width=1200, height=600)
polar.add("A", [1, 2, 3, 4, 3, 5, 1], radius_data=radius,
type='barRadius', is_stack=True)
polar.add("B", [2, 4, 6, 1, 2, 3, 1], radius_data=radius,
type='barRadius', is_stack=True)
polar.add("C", [1, 2, 3, 4, 1, 2, 5], radius_data=radius,
type='barRadius', is_stack=True)
polar

5. 折线图

1
2
3
4
5
6
7
8
9
from pyecharts import Line

attr = ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
v1 = [5, 20, 36, 10, 10, 100]
v2 = [55, 60, 16, 20, 15, 80]
line = Line("折线图示例")
line.add("商家A", attr, v1, mark_point=["average"])
line.add("商家B", attr, v2, is_smooth=True, mark_line=["max", "average"])
line

6. 3D折线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pyecharts import Line3D

import math
_data = []
for t in range(0, 25000):
_t = t / 1000
x = (1 + 0.25 * math.cos(75 * _t)) * math.cos(_t)
y = (1 + 0.25 * math.cos(75 * _t)) * math.sin(_t)
z = _t + 2.0 * math.sin(75 * _t)
_data.append([x, y, z])
range_color = [
'#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
'#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
line3d = Line3D("3D 折线图示例", width=1200, height=600)
line3d.add("", _data, is_visualmap=True, visual_range_color=range_color,
visual_range=[0, 30], grid3d_rotate_sensitivity=5)
line3d

7. 散点图

1
2
3
4
5
6
7
8
from pyecharts import Scatter

v1 = [10, 20, 30, 40, 50, 60]
v2 = [10, 20, 30, 40, 50, 60]
scatter = Scatter("散点图示例")
scatter.add("A", v1, v2)
scatter.add("B", v1[::-1], v2)
scatter

8. 3D散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pyecharts import Scatter3D

import random
data = [
[random.randint(0, 100),
random.randint(0, 100),
random.randint(0, 100)] for _ in range(80)
]
range_color = [
'#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
'#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
scatter3D = Scatter3D("3D 散点图示例", width=1200, height=600)
scatter3D.add("", data, is_visualmap=True, visual_range_color=range_color)
scatter3D

9. 地图

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
36
37
38
39
40
41
42
43
from pyecharts import Geo

data = [
("海门", 9),("鄂尔多斯", 12),("招远", 12),("舟山", 12),("齐齐哈尔", 14),("盐城", 15),
("赤峰", 16),("青岛", 18),("乳山", 18),("金昌", 19),("泉州", 21),("莱西", 21),
("日照", 21),("胶南", 22),("南通", 23),("拉萨", 24),("云浮", 24),("梅州", 25),
("文登", 25),("上海", 25),("攀枝花", 25),("威海", 25),("承德", 25),("厦门", 26),
("汕尾", 26),("潮州", 26),("丹东", 27),("太仓", 27),("曲靖", 27),("烟台", 28),
("福州", 29),("瓦房店", 30),("即墨", 30),("抚顺", 31),("玉溪", 31),("张家口", 31),
("阳泉", 31),("莱州", 32),("湖州", 32),("汕头", 32),("昆山", 33),("宁波", 33),
("湛江", 33),("揭阳", 34),("荣成", 34),("连云港", 35),("葫芦岛", 35),("常熟", 36),
("东莞", 36),("河源", 36),("淮安", 36),("泰州", 36),("南宁", 37),("营口", 37),
("惠州", 37),("江阴", 37),("蓬莱", 37),("韶关", 38),("嘉峪关", 38),("广州", 38),
("延安", 38),("太原", 39),("清远", 39),("中山", 39),("昆明", 39),("寿光", 40),
("盘锦", 40),("长治", 41),("深圳", 41),("珠海", 42),("宿迁", 43),("咸阳", 43),
("铜川", 44),("平度", 44),("佛山", 44),("海口", 44),("江门", 45),("章丘", 45),
("肇庆", 46),("大连", 47),("临汾", 47),("吴江", 47),("石嘴山", 49),("沈阳", 50),
("苏州", 50),("茂名", 50),("嘉兴", 51),("长春", 51),("胶州", 52),("银川", 52),
("张家港", 52),("三门峡", 53),("锦州", 54),("南昌", 54),("柳州", 54),("三亚", 54),
("自贡", 56),("吉林", 56),("阳江", 57),("泸州", 57),("西宁", 57),("宜宾", 58),
("呼和浩特", 58),("成都", 58),("大同", 58),("镇江", 59),("桂林", 59),("张家界", 59),
("宜兴", 59),("北海", 60),("西安", 61),("金坛", 62),("东营", 62),("牡丹江", 63),
("遵义", 63),("绍兴", 63),("扬州", 64),("常州", 64),("潍坊", 65),("重庆", 66),
("台州", 67),("南京", 67),("滨州", 70),("贵阳", 71),("无锡", 71),("本溪", 71),
("克拉玛依", 72),("渭南", 72),("马鞍山", 72),("宝鸡", 72),("焦作", 75),("句容", 75),
("北京", 79),("徐州", 79),("衡水", 80),("包头", 80),("绵阳", 80),("乌鲁木齐", 84),
("枣庄", 84),("杭州", 84),("淄博", 85),("鞍山", 86),("溧阳", 86),("库尔勒", 86),
("安阳", 90),("开封", 90),("济南", 92),("德阳", 93),("温州", 95),("九江", 96),
("邯郸", 98),("临安", 99),("兰州", 99),("沧州", 100),("临沂", 103),("南充", 104),
("天津", 105),("富阳", 106),("泰安", 112),("诸暨", 112),("郑州", 113),("哈尔滨", 114),
("聊城", 116),("芜湖", 117),("唐山", 119),("平顶山", 119),("邢台", 119),("德州", 120),
("济宁", 120),("荆州", 127),("宜昌", 130),("义乌", 132),("丽水", 133),("洛阳", 134),
("秦皇岛", 136),("株洲", 143),("石家庄", 147),("莱芜", 148),("常德", 152),("保定", 153),
("湘潭", 154),("金华", 157),("岳阳", 169),("长沙", 175),("衢州", 177),("廊坊", 193),
("菏泽", 194),("合肥", 229),("武汉", 273),("大庆", 279)]

geo = Geo("全国主要城市空气质量", "data from pm2.5", title_color="#fff",
title_pos="center", width=1200,
height=600, background_color='#404a59')
attr, value = geo.cast(data)
geo.add("", attr, value, visual_range=[0, 200], visual_text_color="#fff",
symbol_size=15, is_visualmap=True)
geo

基于MarkDown的Hexo博客生成系统

发表于 2018-06-18 | 分类于 技术杂项

0X00. 前言

Blog系统其实有很多包括sina、简书等平台Blog系统,也有基于主机自己搭建的Wordpress等CMS系统。知道github后就选用了github的静态站点服务,现在本Blog就是承载在github.io上。

静态站点生成和Blog文章管理,本人接触到的主要是Jekyll和Hexo,Jekyll大概是在两年前用了一段时间,但觉得学习曲线陡峭,同时也发现了Hexo相对友好且容易上手,所以选用了Hexo作为静态网站的管理工具。

网上有很多关于Github的静态站点服务和Hexo教程,本文就不赘述,本文主要记录Markdown及Hexo插件的一些安装和使用小技巧。关于Github静态站点服务和Hexo建议查看官方文档:

Github Page服务:https://pages.github.com/
Hexo Doc:https://hexo.io/docs/

0X01. 关于Markdown

Hexo的所有文章都是使用Markdown作为标记语言生成的,Markdown作为标记语言可以用任何文本编辑工具编辑。在这过程中我使用过很多markdown的编辑器,包括利用插件实现的VIM的版本、Atom的版本,最后还是使用了Typora,很容易上手的一个markdown编辑器。
安装和下载的地址:https://typora.io/

1. Pandoc

Pandoc插件提供了文档的各种格式的输出功能,如果你需要保存文档至其他格式,包括PDF、Word、Html等等开源格式。
下载和文档地址:http://www.pandoc.org/

2. Mermaid

Mermaid,本人觉得是Markdown中最牛逼的插件没有之一。以下是实现的一些示例

sequenceDiagram
    participant Alice
    participant Bob
    Alice->>John: Hello John, how are you?
    loop Healthcheck
        John->>John: Fight against hypochondria
    end
    Note right of John: Rational thoughts 
prevail... John-->>Alice: Great! John->>Bob: How about you? Bob-->>John: Jolly good!
graph LR
A[Hard edge] -->B(Round edge)
    B --> C{Decision}
    C -->|One| D[Result one]
    C -->|Two| E[Result two]

还有复杂的甘特图:

        gantt
        dateFormat  YYYY-MM-DD
        title Adding GANTT diagram functionality to mermaid

        section A section
        Completed task            :done,    des1, 2014-01-06,2014-01-08
        Active task               :active,  des2, 2014-01-09, 3d
        Future task               :         des3, after des2, 5d
        Future task2               :         des4, after des3, 5d

        section Critical tasks
        Completed task in the critical line :crit, done, 2014-01-06,24h
        Implement parser and jison          :crit, done, after des1, 2d
        Create tests for parser             :crit, active, 3d
        Future task in critical line        :crit, 5d
        Create tests for renderer           :2d
        Add to mermaid                      :1d

        section Documentation
        Describe gantt syntax               :active, a1, after des1, 3d
        Add gantt diagram to demo page      :after a1  , 20h
        Add another diagram to demo page    :doc1, after a1  , 48h

        section Last section
        Describe gantt syntax               :after doc1, 3d
        Add gantt diagram to demo page      : 20h
        Add another diagram to demo page    : 48h

文档地址在:
https://support.typora.io/Draw-Diagrams-With-Markdown/

Mermaid的实现满足了工作中大部分需求。

0X02. 关于Hexo配置及插件

1.设置标签和分类目录

本配置都是在根目录下的_config.yml文件中修改:

1
2
3
4
5
6
7
8
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:

2. Theme

本人选择的是主题Next,大家一致觉得比较高质量的主题,在这主题下有4个子主题,笔者采用了Mist.

1
2
$ cd hexo
$ git clone https://github.com/theme-next/hexo-theme-next themes/next

安装后,需要在HEXO配置文件_config.yml中配置主题

1
theme: next

然后进入themes/next文件夹中修改配置文件_config.yml,设置子主题。
注意!四个子主题只能选择一个!

1
scheme: Mist

3. Mermaid

在typora中可以解析mermaid,但是hexo不会解析mermaid,需要安装插件hexo-filter-mermaid-diagrams,地址在https://github.com/webappdevelp/hexo-filter-mermaid-diagrams
这里有几个坑!
官方文档中没有npm口令,但安装可以直接用口令:

1
npm install hexo-filter-mermaid-diagrams

安装后需要在hexo的配置文件_config.yml中添加以下代码:

1
2
3
4
5
6
# mermaid chart
mermaid: ## mermaid url https://github.com/knsv/mermaid
enable: true # default true
version: "7.1.2" # default v7.1.2
options: # find more api options from https://github.com/knsv/mermaid/blob/master/src/mermaidAPI.js
#startOnload: true // default true

最后需要在foot文件中添加解析代码,官方文档中使用的是pug和ejs作为脚本语言,但next主题是使用swing做脚本语言的,并且文件名有些差异。在next主题下,文件地址在:themes\next\layout_partials,文件名为:footer.swig,需要在文件末尾加上如下代码:

1
2
3
4
5
6
7
8
{% if (theme.mermaid.enable) %}
<script src='https://unpkg.com/mermaid@{{ theme.mermaid.version }}/dist/mermaid.min.js'></script>
<script>
if (window.mermaid) {
mermaid.initialize({theme: 'forest'});
}
</script>
{% endif %}

4. Assert

打开资源文件夹选项,修改hexo配置文件_config.yml

1
post_asset_folder: true

至此,在使用hexo发布博客的过程中遇到的一些log于此。遇到问题多看文档,终会解决的。

The First 写在30岁来临之前...

发表于 1988-07-08 | 分类于 人生感悟

这篇文章是正式写Blog的第一篇。其实在此次折腾Blog之前,已经最少有5次使用各种平台,各类工具写文章,依旧没有成型下来。在临近30岁之时,感觉自己需要把思想(或者说瞎想)、学习感悟、人生阅历给记录下来,所以以此开始自己的Blog之旅。

1988年7月8日,是我的生日,人生的起点,所以这篇文章的date定为了1988-07-08 。这也算是我新的征途的开始…

Nullts

Nullts

人生本就虚无,所谓永恒的意义也只是经历的一切。

7 日志
9 分类
20 标签
© 2020 Nullts
由 Hexo 强力驱动
主题 - NexT.Mist