CrazyAirhead

疯狂的傻瓜,傻瓜也疯狂——傻方能执著,疯狂才专注!

0%

问题

Maven设置了打包,没有包含spring.factories

知识盲点

  1. Springboot的自动配置
  2. Maven的Resource

背景

之前采用Sping Config Server做为配置中心,使用Git做为数据存储和版本控制。整体来说问题不太,可用,便不够商用,或者要做很多拓展。比如更新参数时,需要推送Git,重启服务。如果需要动态更新,需要配置Git服务器的WebHook,设置服务的RefreshScope,同时为了减少WebHook的配置,需要加上Spring Cloud Bus(同时引及RabbitMQ或者Kafka)。另外对不同环境的配置不友好,能过Profile来配置,但配置杂乱,虽然后面通过Git分支加环境变量解决,但管理还是不方便。带着这样的一些问题,碰到了Apollo配置中心,Apollo的很多功能直接就解开了我之前的一些疑惑,那还说什么呢?拿来用就好了。

Apollo配置中心

Apollo配置中心文档丰富,直接看官方文档就好,看了之后你也会喜欢上他。以下是官网的功能说明:

  • 统一管理不同环境、不同集群的配置
    • Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。
    • 同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等
    • 通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖
  • 配置修改实时生效(热发布)
    • 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。
  • 版本发布管理
    • 所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。
  • 灰度发布
    • 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例。
  • 权限管理、发布审核、操作审计
    • 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。
    • 所有的操作都有审计日志,可以方便的追踪问题。
  • 客户端配置信息监控
    • 可以方便的看到配置在被哪些实例使用
  • 提供Java和.Net原生客户端
    • 提供了Java和.Net的原生客户端,方便应用集成
    • 支持Spring Placeholder, Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+)
    • 同时提供了Http接口,非Java和.Net应用也可以方便的使用
  • 提供开放平台API
    • Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。
    • 不过Apollo出于通用性考虑,对配置的修改不会做过多限制,只要符合基本的格式就能够保存。
    • 在我们的调研中发现,对于有些使用方,它们的配置可能会有比较复杂的格式,如xml, json,需要对格式做校验。
    • 还有一些使用方如DAL,不仅有特定的格式,而且对输入的值也需要进行校验后方可保存,如检查数据库、用户名和密码是否匹配。
    • 对于这类应用,Apollo支持应用方通过开放接口在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制
  • 部署简单
    • 配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少
    • 目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来
    • Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数

      小结

      通过Apollo配置中心改进了原有Spring Config Server的使用不便。同时如果你的团队使用灰度发布的话,会加深开关驱动开发的了解。

在年会上董事长总结时,说到了管理的铁三角——“人-事-法”,说管理者需要从做事用人到用人做事的思想转变,因人成事,说人和事是一体两面,同时指出法是制度,是机制,是为了降低对人的依赖。这让我想起在雷.达里奥《原则》一书中,有一段对管理原则的描述,我认为他将三者的关系描述得很清楚。

团队的价值观和原则一旦清晰明了,团队的工作方式(也就是团队文化)将渗透于团队的方方面面,包括如何制定目标、发现问题、诊断问题、设计解决方案、落实方案。人认为团队里关系应该是这样的:

团队文化

清晰传递团队的良好文化非常重要,但这只是“魔法公式”的一半,另一半是优秀的员工,他们的价值观、能力、技能都和公司文化相得益彰。
每个公司都像一台机器,为了实现目标而运行着,这台机器会产生结果。将目标和结果进行对比,机器的操作者可以了解机器的运行状态,机器的负责人要把这种反馈循环利用好,才能更好地提升机器的性能。基于反馈,这台机器才能调整与提升。这台机器由两块组成——文化与员工。如果结果与目标不符,那机器肯定出问题了,也就是文化和员工出问题了。要让这台机器发展延续下去,就得诊断问题,设计改进方案,落实改进措施。简而言之,这个不断进化的过程如下图所示,花一分钟好好看看,自己思考一下。

团队机制

在这台机器里,这样的过程运行得越多越有效率,进化的速度就越快。

看了燃点,发现投资人也会更多的关注创业者的品质,认为是创始人是成事的关键。

最近在极客时间看的刘建国的《技术管理实战36讲》中,也讲到管理团队就是带人,做事,建机制。其中有一段关于“关于到底是人靠谱还是机制靠谱”

很多管理者都认为,事情都是人做的,人如果足够靠谱,机制就没什么用了。对此,我的看法是,人的靠谱度的方差比机制大,即,人靠谱的时候比机制靠谱,人不靠谱的时候会比机制更加不靠谱。即便是最靠谱的员工,也会由于身体状态、精神状态、情绪状态以及外部干扰变得偶尔不靠谱,而机制的意义在于,当人不靠谱的时候,事情也不至于变得很差。所以,机制是为了保证做事的“下限”的。同时,机制很好的迁移性和传承性,不会随着某个人的缺倦而产生大的影响。因此,必要的机制是不可或缺的。

而书中对如何保障机制了执行也做了提供了最少关键节点检查法,如果你对这方面的内容感兴趣,可以扫码订阅本书。
技术管理实战36讲

Windows安装了Git之后,右键菜单中多了个Git Bash Here,挺好用的(省去了cd命令),于是对于cmd也在这样的需求。在Win7时可用Shift+右键,看到Open Cmd Here,而Win10打开的是Power Shell,最新的版本好像连Power Shell也没有了。

大家可能也知道,Windows家的很多东西都是可以通过修改注册表来实现的。下面是一段验证可行的注册表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\cmd_here]

@="Cmd Here"
"Icon"="cmd.exe"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\cmd_here\command]
@="\"C:\\Windows\\System32\\cmd.exe\""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\cmdPrompt]
@="Cmd Here"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\cmdPrompt\command]
@="\"C:\\Windows\\System32\\cmd.exe\" \"cd %1\""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\cmd_here]
@="Cmd Here"
"Icon"="cmd.exe"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\cmd_here\command]
@="\"C:\\Windows\\System32\\cmd.exe\""

将上述文档保存为.reg文件,双击运行。右键选择Cmd Here,打开CMD窗口并进入当前目录。

参考链接

win10下右键菜单添加“打开cmd”

  • Spring Boot
  • kotlin

Kotlin简介

Kotlin是JetBrains公司开发的静态编程语言,它运行在JVM之上,它是面向对象的语言但吸收了很多函数式编程的特性。以下是一些它比较有趣的特性:

  • Kotlin是一种静态类型语言,但因为它的类型推断,能有动态语言的编程体验,同时性能也和纯Java一样。
  • 支持属性
  • 相对轻量型的标准库
  • 易学,Java开发者可以快速理解这门语言
  • 支持Java互操作,100%兼容Java
  • 对Android开发友好
  • 内置不变性和空安全支持
  • 代码易读,编码高效
  • 拓展类库不需要继承或者装饰模式
  • 不需要分号(;)

创建项目

使用IDEA的安装向导创建应用,File>New>Project, 然后选择Spring Initializr。接着按向导进行设置如下参数:

  • Package name: “blog”
  • Artifact: “blog”
  • Type: Gradle Project
  • Language: Kotlin
  • Name: “Blog”
  • Dependencies: “Web”, “Mustache”, JPA” and “H2”

    项目结构

    Gradle构建

    插件

    build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
buildscript {
ext {
kotlinVersion = '1.2.41'
springBootVersion = '2.0.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

编译选项

build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}

依赖

build.gradle

1
2
3
4
5
6
7
8
9
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-mustache')
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
testCompile('org.springframework.boot:spring-boot-starter-test')
}

应用

src/main/kotlin/blog/BlogApplication.kt

1
2
3
4
5
6
7
8
9
10
11
package blog

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class BlogApplication

fun main(args: Array<String>) {
runApplication<BlogApplication>(*args)
}

src/main/kotlin/blog/BlogApplication.kt

1
2
3
4
5
fun main(args: Array<String>) {
runApplication<BlogApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
}
}

创建Controller

src/main/kotlin/blog/HtmlController.kt

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

import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.ui.set
import org.springframework.web.bind.annotation.GetMapping

@Controller
class HtmlController {

@GetMapping("/")
fun blog(model: Model): String {
model["title"] = "Blog"
return "blog"
}

}

创建模板

使用Mustache templates.
src/main/resources/templates/header.mustache

1
2
3
4
5
<html>
<head>
<title>{{title}}</title>
</head>
<body>

src/main/resources/templates/footer.mustache

1
2
</body>
</html>

src/main/resources/templates/blog.mustache

1
2
3
4
5
{{> header}}

<h1>{{title}}</h1>

{{> footer}}

通过运行BlogApplication.kt的main函数启动应用, 打开http://localhost:8080/, 我们就可以看到标题”Blog”。

小结

本文主要内容来自Spring官网案例,可能过参考链接查看详细内容。通过IDEA简单的配置和简单的Kotlin代码编写,我们就可构建一个基于SpringBoot的样例,能过这个样例是否对Kotlin感兴趣了呢,可以扫码订阅《快速上手Kotlin开发》。

参考链接

https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin
https://spring.io/guides/tutorials/spring-boot-kotlin/
tut-spring-boot-kotlin

问题

升级Java11时,启动Jfinal-club提示如下警告:

1
2
3
4
5
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by net.sf.cglib.core.ReflectUtils$1 (file:/C:/.m2/repository/cglib/cglib-nodep/3.2.5/cglib-nodep-3.2.5.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of net.sf.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

解决

增加JVM选项–add-opens java.base/java.lang=ALL-UNNAMED

参考链接

https://stackoverflow.com/questions/46671472/illegal-reflective-access-by-org-springframework-cglib-core-reflectutils1

  • java
  • list

问题

1
2
3
4
5
6
7
String to = "1;2;3";
String cc = "1;2;3";
String[] toSplit = to.split(";");
List<String> list = Arrays.asList(toSplit);
String[] ccSplit = cc.split(";");
List<String> temp = Arrays.asList(ccSplit);
list.addAll(temp);

原因

List.addAll的文档中说,如果列表不支持时,抛出UnsupportedOperationException。

Arrays.asList返回的是一个定长的列表,不能往这个列表添加数据。

解决

1
List<String> list = new ArrayList<>(Arrays.asList(toSplit));

参考链接https://stackoverflow.com/questions/25624251/list-addall-throwing-unsupportedoperationexception-when-trying-to-add-another-li

以下内容是极客时间《技术与商业案例解读》专栏的摘录,本专栏由徐飞博士撰写。可以订购该专栏阅读更多精彩解读,开拓眼界,了解互联网发展历史和创业经验。

SAP 是总部位于德国的全球最大的 ERP 公司。作为一家重量级的企业应用软件公司,SAP 曾经有过一段风光的日子。

但是而后的日子也开始不好过起来。

日子不好过的主要原因是 SAP 的软件需要跑在数据库上,而备选的数据库一般来说不是 IBM 的 DB2,就是 Oracle。本来两者和 SAP 的软件配合,相得益彰,曾经一度合作得很愉快。但随着 Oracle 开始进军企业级软件市场,把手伸到 SAP 的地盘来,SAP 的日子就开始不好过起来。

Oracle 在 21 世纪初进行了一系列的并购,包括收购了 Siebel 和仁科等重要的企业级软件企业,把自己从底层数据库到企业级软件的体系补全了。这样一来,SAP 就麻烦了,因为自己的软件依赖于对方的数据库,而对方却还能够提供类似的企业级软件。

好在还有一个 IBM 的 DB2 可以用。SAP 一度和 IBM 合作,希望两者的结合可以给自己带来所谓的强强联合。但是 IBM 的 DB2 却一直面临着诸多问题,比如本身就不是市场上最好的数据库,人才流失又很严重。所谓的合作开展起来,效果却非常有限。

在这个背景下,SAP 开展了一场技术与忽悠并存的战略大跃进,也就是 SAP 著名的 HANA 战略。HANA 的出现对 SAP 和业界都产生了巨大的影响。其实施的过程可谓精彩绝伦,堪称一部大制作的“影片”。

今天我就来讲一讲这个 SAP 的 HANA 战略。

让我们先把时间倒回到 2009 年。这一年,数据库的两大顶级会议之一的 SIGMOD 在罗德岛召开。我最后一次以 PhD 的身份参加 SIGMOD,所以对这个会议印象深刻。这种会议一般都会有赞助商。出钱多的金主很多时候会给一个 Keynote 的讲座。

2009 年的金主是 SAP。这多少有点让人大跌眼镜。一个做企业级软件的公司,来一个数据库顶级会议上大把撒钱,怎么看怎么怪。

在这次大会上,SAP 董事会主席兼创始人之一的哈索·普拉特纳(Hasso Plattner)给了这样一个 Keynote:A Common Database Approach for OLTP and OLAP Using an In-memory Column Database。这个 Keynote 宣告了 SAP 要搞一个内存数据库,它的名字叫 HANA。

SAP 要搞数据库,这可是一件大事情。一个做应用软件的要进军数据库市场,说明“兔子急了要咬人”了。但是企业级软件毕竟是应用软件,而数据库是基础架构软件。就像一个“做菜高手”突然说要开始“杀鸡”,先不说对方哪里来的底气,最起码外界对这个“做菜高手”的看法,肯定是见仁见智的。

HANA 是 High-Performance Analytic Appliance 的简称。SAP 要做的这个数据库,作为一个“做菜高手”进军“杀鸡市场”的第一炮,打得很响亮。按照 SAP 的宣传,它有着市面上传统的数据库很多不具备的特性。

下面我们可以一起了解一下这些特性,这很有必要。
第一,HANA 选择了按列存储的同时支持事务处理。传统数据库是按行存储的,数据仓库近些年来才开始按照列式存储。按行存储对事务处理方便,但是不利于分析处理;按列存储则相反。但是这两者的不利于程度是有所不同的。

通常来说,一个数据库如果同时支持事务处理和分析处理,那么数据库厂商会选择按行存储,因为按列存储的同时支持高效率的事务处理是非常难的。但是 HANA 却选择了按列存储的同时还支持事务处理,这个用数据库界“老司机”的话来说就是,要么是艺高人胆大,要么是无知者无畏。

第二,做出把所有的数据都放在内存里这个假设。今天来看,内存不是很贵了,但是在 2009 年敢做出那样的假设胆子就不是一般的大了。一个数据库一旦数据都在内存里,很多传统数据库的基本假设就都不一样了,做法当然也就很不一样。

所以 HANA 在很多演示的时候,查询极快。一个在 Oracle 或者 DB2 上需要跑一天才能做出来的报表查询,在 HANA 那儿 3 秒钟搞定。对,就是这么快。当然,其实查询是精心挑选的,能够存储这么多数据的机器的配置是非常高的。

第三,因为 HANA 选择了在一个系统同时支持事务处理和分析查询,这就让 HANA 的数据不需要额外 ETL,企业也不需要为分析查询专门配备另外一份列存的数据。某种程度上,HANA 宣称自己节省了企业的消耗,也是对的。而且因为两者共享数据,分析查询的时候能够查询的数据就非常新了。这对企业来说也是非常有必要的。

第四,HANA 几乎完整地整合了 R 的功能,并且把 SAP 业务相关的很多功能直接在 HANA 内部实现了。这有点反计算机软件构架里面的封装。然而在内存数据库的环境下让数据离业务相关计算更近,无疑是一种效率上极其有效的策略。

第五,HANA 采用了现代数据库里常用的 Shared-nothing 的体系架构。这种体系架构数据被纵向按照某个主键切分,每台机器只需要负责自己的部分。这让 HANA 具备了非常灵活的资源配置,而且加了机器查询也就会变得更快,立竿见影。简而言之,HANA 的体系架构很新。

综上所述,HANA 在技术上是很有创新的,而且单纯从 SAP 公布出来的这些技术细节来看,HANA 的确是具备了在很多方面对传统数据库发起挑战的能力。所以,一个“做菜”的,看起来“杀鸡”也杀得很漂亮。很多人不得不为 SAP 精彩的 HANA 数据库疯狂打 Call 了。

由于 SAP 的这个举措,首先受到伤害的是和 SAP 合作的 IBM 的 DB2 组了。毕竟,本来是难兄难弟抱团取暖,现在变成了一个人冲锋陷阵,抛弃了老伙伴。

其次受到威胁的当然是那个坐在数据库领域第一把交椅上的 Oracle。试想一下,原来用 SAP 的必须上 Oracle,而用 Oracle 的还可以搭自己家里的企业级软件。这让 Oracle 处于多有利的地位呀!但突然之间局势就变了,SAP 有自己的数据库了,而且还很快、很厉害、很先进。接下来 Oracle 的这个生意就不好做了。

但是对 2009 年的 SAP 来说,HANA 这个吸引眼球的宣传,一下子让原本已经成为或者即将成为二流公司的 SAP 回到了聚光灯前,不管产品有没有做出来,最起码先把风头抢占了。SAP 公司 HANA 战略的实施,当得上商业教科书的经典案例。对于一个 2009 年就吹起来的、但是却没有实际产品的 HANA 数据库,SAP 的开发和商业化道路概括来说就是四个字:心黑胆肥。

2010 年开始,SAP 在大力宣传 HANA 的时候,并没有大规模地卖 HANA,而是非常有重点地挑了几个人傻钱多的企业开始做内测。这些企业不但钱多,而且还愿意当小白鼠。2011 年以后,HANA 面向的对象稍微多了一点,但主要还是非常有钱的大型企业,比如德国电信、中石油、中石化这种。可以说一般没钱的企业是享受不到充当 HANA 小白鼠资格的。

HANA 需要内存 64 GB 以上的机器,但是一般来说 64 GB 跑起来大数据还是不够快。所以通常需要更多的钱买非常贵的硬件。而 HANA 的软件的最低配置是 30 万美元起。所以软硬件一起更是耗资巨大。从 2011 年到 2014 年,SAP 一直对 HANA 相关的产品定以非常高的价格。基本上这个产品给人的感觉就是:只有有钱的公司才能用得起,没钱的就算了。

所以市面上对 HANA 的各种抱怨,主要都集中在了 HANA 高昂的价格上了。然而这其实也是 SAP 想要的。
• 一方面,SAP 的高价让大家把对 HANA 的关注都集中到了价格上;
• 另外一方面,SAP 通过高价获得了不少优质客户和源源不断的金钱,更是从这个高价的过程里获得了对产品来说非常重要的形象问题:HANA 就是“高大上”的代表。

另外,因为价格高,所以实际上真正使用 HANA 的用户并不多,而且这些用户的硬件多半都是高配版。这样,HANA 即使有这样或那样的问题,暴露在大众面前的机会也不多。所以在收获金钱的同时,SAP 也给 HANA 的逐步完善赢得了很多的时间。

SAP 宣传的大胆还体现在对 HANA 的宣传上。SAP 宣传 HANA 的时候,把 HANA 和 Oracle 的产品做对比。SAP 表示,HANA 是基于最新硬件和研究的新一代数据库,代表着数据库的未来;而 Oracle 则是一个已经存在了很多年的老朽的东西,不代表未来。

这个宣传,我们先不管是不是言过其实,但它的实际效果的确是非常好。那些不差钱的企业,比如中国石油,要的就是最新、最贵的东西。于是世界各地大量有钱的企业排队从 Oracle 转到 HANA 上。这些企业有中国的,有日本的,还有欧洲、美洲的。很多企业都是被 HANA 这种舍我其谁的势态给吸引过来的。

说起来真的是一物降一物。这么多年来,HANA 的出现,第一次对 Oracle 的基本盘产生了动摇。在这之前不管是 DB2 还是 SQL Server,Oracle 都不屑一顾。在 Oracle 看来,那些无非是跟在后面吃点“残羹冷炙”,算不得威胁。而 HANA 不断抢占 Oracle 的用户,让 Oracle 也开始着急起来。Oracle 在商业上显得非常被动。

并且后续 Oracle 一系列的发布:从 Timesten、Exalytics、Exadata 到 Oracle 12c In-Memory Option,简直是用实践再次证明了自己就是 HANA 的一个追随者,而 SAP 才是内存数据库的开拓者。所以很多人更懒得去理会那个亦步亦趋的 Oracle 了。Oracle 慌了,可能 Oracle 也没有想到,自己当初抢占 SAP 领地,SAP 这次也同样还回来了。

SAP 宣传 HANA 的另外一个十分胆大的地方就是敢吹,什么都敢吹。每次都是新功能、新特性先做一个半成品,就发布出去给客户用。不但发布出去,还在客户文档里面大肆吹多牛多牛。而实际上呢?这些半成品的 Bug 一堆又一堆。举个例子,HANA 在 2011 年的时候连 High availability 都还不具备,居然就开吹 HANA 不需要 High availability。然后用户们竟然还真的信了。

当然仅仅靠吹,牛皮总会有吹破的时候。所以 SAP 对 HANA 的商业实施的另外一举措就是疯狂地开发和发布新版本。在 SAP 把 HANA 推出市场以后,基本上开发团队做到了半个月到一个月一个新版本。每次新版本都会增加很多半成品的新功能,与此同时,也把前面几个版本里大的 Bug 都修复好。

这个做法的好处是:一方面,用户当了小白鼠测试了新功能,减少了自己投入在测试上面的成本;另外一方面,修复得如此及时,用户体验非常好。客观一点说,4 年发布了 80 个新版本,而且每两个版本之间的差异还是很大的,也就是说半年后和半年前的 HANA,简直就不是同一个软件。这是非常不容易且难得的高效率开发。

不仅如此,SAP 还在公司内部把 HANA 作为公司战略高度的产品来推广。具体来说,销售部门卖产品的业绩要重点看 HANA 卖了多少。开发团队各个产品组的新功能必须先支持 HANA 才可以去开发。至于没有 HANA 能不能跑起来,就不是必要条件了。总之,从宣传到销售到市场到研发一切以支持 HANA 为最高优先级。SAP 在那几年里,一直处于这样一种全力以赴的状态。

当然 SAP 清楚地知道自己很“跛脚”:传统数据库相关的技术积累太过薄弱,所以 SAP 在大张旗鼓开发 HANA 的同时,做的另外一件偷偷摸摸的事情是收购一个数据库厂商。SAP 买下了日子不好过的老牌数据库公司 Sybase。Sybase 虽然这些年产品卖得不好,但是在数据库领域还是有数十年积累的。这些传统数据库的技术,对 SAP 就非常地重要。

获得了 Sybase 的技术支持以后,SAP HANA 的体系立刻变得完整起来。举个例子,以前是所有数据全部在内存里才能用,但是总有人不是土豪,没那么有钱,买不起太高端大内存的机器,怎么办?HANA 后期的完整解决方案里面就有 cold data 存磁盘的办法,当然用的是 Sybase 那儿买的技术。

另外一个特别重要的是实时备份技术,这在任何商用数据库里都很成熟,但是 HANA 一直是“裸奔”的。买了 Sybase 后,就迅速地集成了 Sybase Replication Server。

SAP 偷偷地收购 Sybase,绝对是 SAP 下的一盘大棋里关键而又冒险的一步。成功了,一下子就获得了 Sybase 的技术,从而弥补了 SAP 的先天不足;失败了,HANA 的各种缺陷迟早会暴露出来的。那时 SAP 就会比较难往前走了。

Sybase 到手,关键技术整合起来后,2015 年的 HANA 已经是一个各方面都非常领先的内存数据库,即便是 Oracle 这样的“大佬”也无法有任何的实力可以撼动了。这样一来 SAP 的战略转型就顺理成章了。

对 SAP 来说,有和没有 HANA 是生死攸关的。HANA 战略的成功,无疑是技术和商业上的同时成功。这样的成功称得上是商业教科书的经典案例。

SAP HANA 的故事精彩到可以拍成电影。SAP 的 HANA 战略很成功,徐飞老师说成功的忽悠和成功的执行,就是一个成功的产品,想知道老师是如何总结的,扫码订购该专栏。

最近在微博中看了这个视频。刚好呢,自己练习左手使用筷子三个来月了,对于正确使用筷子算是有一些体验可以分享一下。

在李笑来老师的得到专栏《通往财富自由之路》里中一篇讲关于“学习能力”这个概念的文章,文章中拿了使用筷子做例子,我也是使用这种方式来练习左手用筷子的,所以先引用下该文章内容:

“学会如何正确使用筷子”,其实还真的是个好例子值得反复审视。

现在有两种情况:

  • 你自己知道自己确实不会用筷子;
  • 你自己知道自己能正确用筷子……

若你自己不会用筷子,接下来你要看看自己有没有能力达到学习能力进阶的第二个阶段:通过读书、读教程,学会一项技能;如果你自己确定自己能够正确地使用筷子,那你现在可以尝试再进阶半步:看看自己有没有能力教会别人正确地使用筷子……

我在网上翻了翻,写得最好的教程,居然(其实也很自然)是老外写的,在WikiHow上:

https://www.wikihow.com/Eat-with-Chopsticks

有文字讲解,也有视频示范。先去看看,看看你自己能不能学会?或者想象一下,若是你教别人(比如自己的孩子用筷子),你应该如何教?最重要的关键在哪里?为什么看起来这么简单的事儿能难住2/3以上的人群?

我们总说:屁股决定脑袋。

你所在的位置会决定你看问题的角度,以及应对的方式。对于同一个问题,改变了位置之后,可能看法会截然不同,甚至能够找到更优质的解决方法。

面对“学习”这件事的时候,这句话同样适用。

如果你总是以一个“学生”去要求自己,其实无意间降低了自己的标准。因为你的目标只是学会,或者看似学会。但实际上检验一个人是否真正掌握了一项技能的最好方法,就是让他把这个技能教给别人。

所以如果大家在学习的过程中,脑子里始终想着未来要把它教给其他人,那么对于自己的要求自然会提高,同时我们的学习效率和效果自然也会更好。

这么多年来,我经常拿这事儿当例子,用来证明:

有很多事情,即便是非常简单,都有可能难住一些人一辈子;

这件事儿还能证明:

这么简单的事儿,绝大多数人竟然不会教,甚至连自己的孩子都教不会……只顾着最后在那里发脾气,而后无可奈何……
如果能够仔细观察、最终找到重点的话,基本上是教的人两分种就讲明白,而后学的人五分钟之内就能搞定,随后摆脱一辈子的尴尬的事情。

正确使用筷子

关键之处其实有以下这么两点:

  • 两根筷子中,下面那根一直是处于静止状态的;
  • 张开、夹上的动作,其实来自于上面那一根;
    最为关键的是,如何令下面那根处于稳定状态呢?
  • 下面那根筷子,跟手一共有三个接触点:两端作为支点;
  • 大姆指的根部在中间压住筷子,无名指其实是“反向用力顶住”……
  • 大多数人败在无名指的用力方向上,这个方向搞对了,下面那根筷子就稳定了;
  • 接下来就是练习几分种如何用大姆指和食指控制上面那根筷子并夹住东西……
  • 反复练习,从笨拙到熟练的过程,本质上来看是大脑在建立沟回的过程。

那些之前就会用筷子的人,不妨对比一下,你教的方法、路径、重点,和我的一样吗?不一样的话,比我的更有效吗?如果比我的更有效不妨教教我,我也想有机会提高效率。许多年来,我在教别人如何学习的过程中,顺带帮助很多很多成年人“突然之间开始能够正确熟练地使用筷子这个神奇的东西……”。

当时也不太以为意,只是明确的知道自己的方式是不一样的,表现为下面的那个筷子是用无名指顶住的,而不是中指,上面的筷子是用中指和食指及大姆指夹住的(有点像抓笔),其他方面基本就一样了。效率上是否有优势就不得而知了。另外呢,这篇文章的评论里不少人说改正了自己多年的不正确的方式,或者学会了左手(或右手)用筷子,总之觉得是有用的。

直到这学期署假,儿子幼儿园要求开始教小孩使用筷子时,我才重视起来。儿子是左利手,用匙子和笔都是用左手,用筷子自然也是左手。教小孩呢,我觉得最好的方式是就示范,但我用右手,在示范时儿子还是不太懂。然后呢,我就开始在中午吃饭的时候练习起了左手用筷子,用的就是上面教的方法。这篇文章是2017年6月发布的,而自己真正开始实践已经是一年多过去了,想想真是刚需决定行动力。

下面说说自己的体验。

刚开始呢,确实很容易就能掌握手抓筷子的方式,比如很容易你就能夹起黄豆或者花生之类的东西。

接下来发现夹米饭时,上面的筷子很容易和下面的筷子错开,而不能夹稳,此时右手就会想去帮忙,或者说右手的食指就感觉在动一样。你或许听说过,为了帮助左手受伤的人恢复需要把右手绑起来,所以自己逐步通过固定手在桌子上或者揣在口袋里来克服。

食物总是多种多样,左手用筷子时发现碰到一些比较大的食物(比如红烧肉)时,就张不开,夹不起来。一开始比较粗暴一点,直接用一只筷子插进去。大致练习左手两个月之后,又点了一次红烧肉,突然想能不能用自己右手的方式呢,因为自己右手用了三个手指控制能张得比较开。可是发现居然不能很快的换一种方式,就像左手只记住了上面的方法,用另一种方式就很难,或者总是想换到之前的那种。我是大学时因为和同学一起玩夹花生米的游戏对自己的夹法有所改进的,之前是什么模样,竟然没有多少印象了。之后换了回来,发现无名指往上用力的体会也会深一些,确实能减少上下筷子错开。

左手用了一段时间了,中指顶住筷子的地方还是会疼,是的,你可曾想起刚开始学自行车时会紧紧的抓住车把,就想把他拽下来一样。

应该是还需要时间,还需要练习,反复练习,从笨拙到熟练的过程,本质上来看是大脑在建立沟回的过程。之前评论中回复学会正确使用筷子的人有多少是真正在使用并从中获益呢,或许只有他们自己知道了。但对于我自己来说,要教会儿子正确使用筷子我是绝对有信心了。