前言

  1. 人们的行为和决策经常偏离理性,远非完美

  2. 竭尽全力追求,与最终能不能作出最好的决策是两回事

  3. 从理论上来说,理论和实践没有什么不同,但到了实践中,两者就天壤之别

1.相对论的真相

诱饵效应:人脑思维所受的束缚,总是靠观察周围事物以确定彼此的关系,只有A和B给我们选的时候,我们很难做比较,但当有一个较差的A-加入进来的时候,我们会更容易选择A,这就是比较的诱饵效应,我们喜欢比较和攀比,以及嫉妒他人也是这个原因。

怎么做: 控制欲望,选择最合适自己当前的,打破相对论的怪圈。(把你身边那些昂贵的轿车、房子、衣服首饰,换成普通好用的就行。)

2.供求关系的失衡

对于事物的第一印象会影响我们对同类产品的比较,这就是锚定

幼鹅效应与锚定:锚会影响各种购买行为。我们所做出的首次决定,将在日后影响我们的其他决定(关于衣服、食品等)。有的时候我们的选择是追随最初印记的一时冲动。

我们对价格变化的敏感,是两种因素的共同作用:我们对过去的价格和我们想和过去决定保持一致的欲望,而非我们真正的偏好或供求关系的反映。但如果人们记不住过去的价格,价格的变化对需求的影响是很少的。

羊群效应:基于其他人的行为来推断某事物的好坏以决定我们是否效仿;–>“自我羊群效应”,基于自己先前的行为来判断某事物好或者不好;

3.免费的代价

“零”不仅仅是一种特别的价格表示法,还能唤起热烈的情绪,成为非理性兴奋的来源;

免费最大的问题在于,它引诱你在它和另一种商品之间挣扎–引导我们做出不明智的决定。–>在两种产品之间作选择时,常常对免费服务反应过度;

免费使我们忘记不利的一切,人类本能的惧怕损失,选择免费不会有任何损失,而选择不免费的,就会有风险;

怎么做:政府可以利用免费来推行社会政策。而作为理性的消费者,我们要考虑的不是绝对价值,而是相对价值

4.社会规范的成本

社会规范:暗藏在社会本性和共同需求里,一般是友好的、界限不明的、不要求即时回报的,给双方都带来愉悦并不要求立即的对等的回报;

市场规范:不存在友情界限分明,交换是黑白分明的,工资价格租金利息以及成本和盈利,这种关系未必是邪恶与卑鄙的,事实上它同时包括了自立、创新、以及个人主义,意味着利益比较和及时偿还。

市场规范下雇员对雇主的忠诚度常常会减弱,而在社会规范是激励员工保持忠诚度的最好方法:实行弹性工作制、医疗福利、送礼品比奖金更容易培养员工的忠诚度、培养员工一种目的感、使命感和教育的自豪感。

如果要让市场规范起作用,提钱就足够了,即使不是现金。

市场规范与社会规范不可兼得,而且当二者同时存在时,社会规范必将退出。换言之,社会规范很难重建。金钱到最后经常是最昂贵的激励方式

5.性兴奋的影响

我们很难在冷静状态下判断兴奋状态下的行为:人在理性状态下和性兴奋状态下,情感和行为的反应会有非常大的不同,且会做出错误的预测。

我们在冷静状态下是一个人,兴奋状态下是另外一个人,我们无法做到自控。如何预防这些问题的发生呢?在尚未被诱惑控制前说“不”,了解冷静和激情状态并明白他们对我们的好坏,以及充分应对其后果。

6.拖沓的恶习和自我控制

灌输自制意志是人类总体的目标。一再失败、少有成功则是我们很多痛苦的来源之一。

为了眼前的满足而放弃长远的目标,就是拖沓

怎么解决:设定自我控制的底线,严格限制自由(硬性规定)是治疗拖沓病的最有效手段;另外,给人一种工具让他们自己设定期限,就可以帮助他们完成任务;还有一些方法,比如一个人无法完成健身计划时可以和朋友搭伴;我们也可以将需要处理的事件,拆分成几部分,这样在我们完成一部分后,就相当于到达一个里程碑,这将激励我们去完成接下来需要处理的一部分,激发我们工作的动力

7.所有权的个性

1、对自己所拥有的东西迷恋不能自拔,产生依恋;2、注意力总集中在自己会失去什么,而不是自己会得到什么;3、经常假定别人看待交易的角度和我们一样;4.我们在某种事物上投入越多,感情越深,会产生”宜家效应”;5.我们常常会幻想自己已经得到某样东西,虚拟其所有权,因此渴望越发强烈。

虚拟所有权是所有广告的主要动因:把自己想成所有者、试用则产生所有权情绪涌动、30天退换想到失去就会惶恐,所有权直接改变了我们观察的角度。

解决办法:用非拥有的心态去看待每一桩交易,适当拉开距离,待之以平常之心。(对人也是如此);

8.多种选择的困境

在面临多种选择的时候,我们倾向于为自己保留余地,但同时我们也放弃了别的东西,因为把所有的门开着,会让我们疲于奔命,所以我们要果断地关上该关的门,放弃那些毫无价值的选择。

在吸引力大致相同的两种选择中做取舍是最难的,集中关注两种选择的细微异同时,偏偏没有考虑犹豫不决的后果,无论哪种选择细微差别总是存在的。

9.预期的效应

如果我们事先相信某种东西好,它一般就会好,反之亦然,这除了改变我们的信念外,甚至会改变我们的实际体验。这就是预期的效应。预期会影响到我们对事物甚至自我的认知。

1.预期改变人们对体验的认识与品评,如:评论家对该片的评价高他们就会更加喜欢这部电影、好的环境和盘中的食品的艺术、创建品牌和提高产品的知名度

2.预期可以形成成见,不一定是有害的,成见为我们不断的理解周围复杂的环境提供了便捷

3.尽管成见会影响自己行为,但成见的激活则却绝于我们当时的心理状态和自我认知

4.偏见化思维是绝大多数冲突升级的主要根源

怎么做:不带偏见地提出各自的认知,揭示事实真相。承认人人都存在偏见,容易被固有信念所禁锢,对某些事实视而不见,所以我们需要一个未曾被我们预期影响第三方。

10.价格的魔力

当人们信任一件事情,会产生相应的影响,这就是一种暗示的效应。预期影响感官甚至主观和客观体验

安慰剂和安慰疗法的作用靠的是暗示的力量,形成预期,在医药方面价格能改善体验。其中的机制是信念和条件反射。

11.人性的弱点

人类社会两种本质欲望:取悦他的同类、不愿意得罪他的同类

成本收益法:成长中把社会美德内化了,引导我们发展到超越自己境界

为什么社会上还是有那么多不诚实的现象呢,因为我们内心的诚实尺度只有在考虑重大越轨行为时才被激活,细微越轨则忽视;

怎么做:读《圣经》、《古兰经》或重建职业道德标准,在履行准则的保证上签名。认识到人性的弱点,防患于未然。

12.企业的特权

我们擅长把自己细微的不诚实想法和做法合理化。

即使外部事物不可理解,我们只要尝试从自身所处的环境进行解读,也可以从中收益。

13.啤酒与免费的午餐

个人需求和群体需求的矛盾:那些注重表现自己的独特性的人们更注重个人需求,希望在更融入群体的人则会舍弃个人需求跟随群体需求

免费午餐的观念就是借助工具、方法、政策来改善我们的决策过程,减少决策失误,以使我们心想事成。

1.微服务是协同工作的小而自治的服务

微服务的特点:

1) 协同:服务之间通过进程间通信的方式进行调用,服务之间通过网络使用api来通信,从而增强了服务之间的隔离性,避免耦合。一个进程会暴露几个api。

2) 很小,专注于做好一件事。一件事:内聚,业务的边界即服务的边界。很小,如何算小?时间两周内能完成更换,能很好地和团队结构相匹配

3) 自治:可以独立地部署在PaaS平台上,也可以作为一个操作系统的进程存在

什么时候你不应该使用微服务?当你不了解一个领域的时候,找到服务的限界上下文很难。从头开发的时候,先弄稳定再拆分。

2.如何建模服务

什么样的服务是好的服务?松耦合,高内聚

1) 松耦合:修改一个服务不需要修改另外一个服务,保证服务是可以独立修改和部署

如何做到松耦合?限制两个服务之间的不同调用形式的数量,过度的通信可能会导致紧耦合。

2) 高内聚:改变某个行为,最好能够只在一个地方进行修改

松耦合、高内聚的关键是找到服务的边界。找到问题域的边界就可以确保相关的行为能放在同一个地方,并且他们会和其他边界以尽量松耦合的形式进行通信。

服务的边界划分错误后,后续修复的代价会很大。可以考虑先开发为单块架构,等对业务熟悉后,或者系统稳定后,再把单块架构转换成微服务架构。

3.应该按照业务建模

1) 首先考虑业务的功能,这个上下文是做什么的?

建模服务时,应该将这些功能作为关键的操作提供给其它服务

2) 然后考虑共享的数据,“它需要什么样的数据”。

只考虑数据模型的共享,会导致贫血的服务(只基于crud的服务)。

3) 逐步划分:

a. 首先识别出粗粒度的上下文,如仓库,财务

b. 进一步划分嵌套的上下文,如仓库又可分为:订单处理、库存管理、货物接受等。

c. 根据组织架构决定是使用嵌套的方式(如仓库的粗粒度上下文里嵌套订单处理、库存管理及货物接受等细粒度上下文)还是分离的方式(取消仓库上下文,直接将仓库内部的上下文提升到顶层上下文的层次)。订单处理、货物接收及库存管理如果由同一个团队维护,使用嵌套方式,如果由不同的团队维护,使用分离方式。

4.划分上下文容易犯的错误:技术建模

按照技术接缝对服务进行划分(比如按照RPC分成两层:前端和仓储层,而不是按照业务分层),会导致把上下文内部的api暴露出去,导致紧耦合,这就是所谓的洋葱架构(水平分层架构),虽然不一定是错误,但不是首选的方式。

5.多个微服务的集成方式

常用技术:SOAP、XML-RPC、REST、Protocol Buffers等,针对请求/响应的常用技术:rpc、rest。

  • 同步:发起一个远程服务调用后,调用方会阻塞自己到整个操作的完成。同步可以使用的协作方式:请求/响应
a. 优势:
i. 可以知道调用成功与否
ii. 技术实现简单

b. 劣势:
i. 运行时间长的应用,需要客户端和服务器之间的长连接
ii. 高延迟
  • 异步:调用方不需要等待操作是否完成就可以返回,甚至可能不关心操作完成与否,可以使用的协作方式:请求/响应或者基于事件
a. 优势:
i. 对运行比较长的任务比较有用,否则客户端和服务器之间要开启长连接。
ii. 低延迟
iii. 基于事件的协作方式可以分布处理逻辑,低耦合

b. 劣势:
i. 处理异步通信的技术相对复杂
  • 协同(choreography):告知系统中各个部分各自的职责,具体怎么做的细节留给它们自己,可以用芭蕾舞中的每个舞者来做比喻,通常使用事件驱动的方式,基于事件的异步协作方式常用rabbitmq等消息中间件。
a. 优势:
i. 显著地消除耦合

b. 劣势:
i. 看不到业务流程的进展
ii. 需要额外的工作来监控跨服务的流程,以保证其正确的进行。实际的监控活动是针对每个服务的,但最终把监控的结果映射到业务流程中,在微服务架构里常使用协同方式实现。

6.微服务的部署

持续集成CI能够保证新提交的代码和已有代码进行集成,从而让所有人保持同步。CI服务器会检测到代码已经提交并签出,然后验证代码是否通过编译以及测试能否通过。

持续交付(Continuous Delivery,CD)检查每次提交是否达到了部署到生产环境的要求,并持续反馈这些信息,还会把每次提交当成候选发布版本来对待。CD对多阶段构建流水线的概念进行扩展,从而覆盖软件通过的所有阶段,无论是手动还是自动。

微服务的配置应该单独管理,配置的形式可能是环境的属性文件,或者是传入到安装过程中的一些参数,这样可以避免把生产环境的数据库密码或其他工具密码提交到源代码中。

  • 部署微服务的建议

1.引入PaaS(平台即服务),最大好处是允许你控制运行服务的节点数量,如:Heroku;

2.将主机控制、服务部署等工作自动化,自助式配置单个服务或者一组服务的能力,也可以简化开发人员的工作,理想情况下,开发人员使用的工具链应该和部署生产环境时使用的完全一样,这样方便及早发现问题。

7.微服务测试

微服务架构中测试的复杂度进一步增加,了解测试的类型可用帮助我们尽早交付软件与保持软件高质量之间的平衡。

测试大都是可用自动化测试的,例如性能测试和小范围的单元测试。当然测试也要涵盖服务测试、端到端的测试、部署后的测试、跨功能的测试(非功能性需求)。

8.微服务的监控

微服务的监控的原则:监控小的服务,然后聚合起来看整体

从日志到应用程序指标,集中收集和聚合尽可能多的数据,可用logstash + kibana。

  • 关联标识

一个服务调用最终会触发多个下游的服务调用,更为复杂的初始请求有可能生成一个下游的调用链,并且以异步的方式处理触发的事件。一个非常有用的方法是使用关联标识(ID):在触发第一个调用时,生成一个GUID,然后把它传递给所有的后续调用。类似日志级别和日期,我们也可以把关联标识以结构化的方式写入日志。使用合适的日志聚合工具,就能够对事件在系统中触发的所用调用进行跟踪。

  • 标准化

监控这个领域的标准化至关重要:服务之间的多个接口,可以用很多不同的方式合作来提供功能,需要以全局的视角来规划。

1) 标准格式来记录日志

2) 把所有的指标放到一个地方

3) 为度量提供一个标准名称的列表

4) 使用工具在标准化方面提供帮助

  • 考虑受众

监控收集的数据会触发一些事件,有些数据会触发支持团队立即采取行动。对于查看这些数据的不同类型的人来说,需要考虑以下因素:

1) 现在需要知道什么

2) 之后想要什么

3) 如何消费数据

9.微服务安全问题

1.通过账户和密码进行身份验证和操作授权

2.深度防御:从网络边界,到子网,到防火墙,到主机,到操作系统,再到底层硬件,都需要在这些方面实现安全措施的能力。

2.服务间的身份验证和授权

3.静态数据的安全:按需对数据、文档进行备份、加密解密

了解系统不同部分的威胁级别,知道什么时候考虑传输中的安全,什么时候需要考虑静态安全,或根本不用考虑安全

10.规模化微服务后的故障处理

当微服务规模化后,故障是无可避免的,以往我们总是想尽力避免故障的发生,而当故障实际发生时,我们往往束手无策。我们花了很多时间在流程设计和应用设计的层面上来阻止故障的发生,但实际上很少花费时间思考如何第一时间从故障中恢复过来。

一.从体验上来解决:功能降级

二.从请求/响应上来解决:加入超时机制、断路器、舱壁

三.从处理结果上解决:如果操作是幂等的,我们可以对其重复多次调用,而不必担任会有不利影响

四.从应用上解决:更强大的主机、一台主机一个微服务、关键业务弹性部署、多云服务数据商备份、异地灾备、负载均衡、重构系统、作业队列、重新设计

五.从数据库上解决:扩展数据库,主从复制、读写分离

六.从缓存上解决:客户端、代理服务器和服务器端缓存,但注意设置合适的缓存失效时间

集合List、Set的常用Stream方法

1.List<INSCFeerule>对象集合转换为不重复的INSCFeerule对象属性rulesetid的set集合

List<INSCFeerule> srcRuleList = inscFeeruleDao.selectByFeecontentId(feecontentId);
Set<String> rulesetidList = srcRuleList.stream().map(INSCFeerule::getRulesetid).collect(Collectors.toSet());

2.list集合去重,得到list集合

providerIds=providerIds.stream().distinct().collect(Collectors.toList());

3.判断是否存在符合条件的元素,只要一个符合立刻返回true

boolean isParent=totalInsbListPro.stream().anyMatch((INSBProvider provider)-> StringUtil.isNotEmpty(provider.getParentcode())&& provider.getParentcode().equals(pro.getPrvcode()));

类似还有

noneMatchStream 中没有一个元素符合的才返回 true
list.stream().noneMatch(item->"guizequery".equals(item.getOperator()))

allMatchStream 中全部元素符合传入的 predicate,返回 true

4.将集合inscfees先过滤留下只符合Noti="1"条件的元素,然后映射为自定义的格式String类型数据,最后通过<br>拼接元素返回String类型数据

String temp=inscfees.parallelStream().filter((INSCFeecontent fee)->"1".equals(fee.getNoti())).map((INSCFeecontent fee)->"【"+fee.getDeptname()+" - "+fee.getProvider()+" - "+fee.getVersionno()+"】").collect(Collectors.joining("<br>"));

5.集合元素转为以”,”拼接的String

String newTypeCodeValue=lastTypeCodeList.stream().collect(Collectors.joining(","));

6.List<Map<String,Object>>类型的infoMapList获取key是rulesetid的value的不重复String集合

List<String> addRulesetids=infoMapList.stream().map((Map<String,Object> map)->String.valueOf(map.get("rulesetid"))).distinct().collect(Collectors.toList());

7.List<Map<String,Object>>类型的list获取key是flib_id的value,转为数组类型返回

Arrays.asList(list.stream().map(item -> (String) item.get("flib_id")).toArray();

8.返回特定的结果集合:

List<String> limitLists = forEachLists.stream().skip(2).limit(3).collect(Collectors.toList());

注意skip与limit是有顺序关系的,比如先使用skip(2)会扔掉集合的前两个,然后调用limit(3)会返回前3个

9.按照sortLists里元素的大小进行排序

List<Integer> afterSortLists = sortLists.stream().sorted((In1,In2)->
       In1-In2).collect(Collectors.toList());

10.得到其中长度最大的元素

int maxLength = maxLists.stream().mapToInt(s->s.length()).max().getAsInt();

或者
Optional<Integer> maxLength = maxLists.stream().reduce(Integer::max);

或者
Optional<Object> minObject =objects.stream().min(comparing(Object::getValue));

11.List和Map通过forEach循环过滤得到符合条件的数据

List<Map<String, Object>> queryList = ... ...;
List<Map<String, Object>> policyList = new ArrayList<>();//保存符合条件的数据
 queryList.forEach(map -> {
            map.forEach((k, v) -> {
                if ("policyno".equals(k) && v != null) {
                    policyList.add(map);
                }
            });
        });

12.求和

int sum = numbers.stream().reduce(0, (a, b) -> a + b);

或者
int sum = numbers.stream().reduce(0, Integer::sum);

java8日期常用方法

1.获取当天的日期

System.out.println("---"+LocalDate.now());//---2018-01-17
System.out.println("---"+LocalDateTime.now());//---2018-01-17T14:19:24.525 ,给人阅读的时间戳
System.out.println("---"+Instant.now());//---2018-01-17T06:19:24.525Z,给机器阅读的时间戳

2.获取当前的年月日

LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.printf("Year : %d Month : %d day : %d \t %n", year, month, day); //Year : 2014 Month : 1 day : 14

3.检查两个日期是否相等

LocalDate date1 = LocalDate.of(2014, 01, 14); if(date1.equals(today)){
	//today 2014-01-14 and date1 2014-01-14 are same date
 	System.out.printf("Today %s and date1 %s are same date %n", today, date1);
}

4.获取当前时间,默认的格式是hh:mm:ss:nnn,LocalTime只有时间,没有日期

LocalTime time = LocalTime.now(); System.out.println("local time now : " + time); //local time now : 16:33:33.369

5.判断某个日期是在另一个日期的前面还是后面

LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018, 1, 15);
if(tommorow.isAfter(today)){
     System.out.println("Tomorrow comes after today");
}

6.检查闰年

LocalDate类有一个isLeapYear()的方法能够返回当前LocalDate对应的那年是否是闰年。

7.获取当前时间戳

Instant timestamp = Instant.now();
//What is value of this instant 2018-01-15T10:33:33.379Z
System.out.println("What is value of this instant " + timestamp);

8.使用预定义的格式器来对日期进行解析/格式化,BASICISODATE格式就是yyyy-mm-dd

String str1 = "20180117";
LocalDate formattedstr1 = LocalDate.parse(str1, DateTimeFormatter.BASIC_ISO_DATE);
//Date generated from String 20180117 is 2018-01-17
System.out.printf("Date generated from String %s is %s %n", str1, formattedstr1);

String str2 = "2018-01-17 14:27:30";
LocalDateTime formattedstr2 = LocalDateTime.parse(str2, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//Date generated from String 20180117 is 2018-01-17T14:27:30
System.out.printf("Date generated from String %s is %s %n", str1, formattedstr2);

9.使用自定义的格式器来解析日期,可以转为String类型,DateTimeFormatter是不可变且线程安全的

LocalDateTime arrivalDate = LocalDateTime.now();
try {
    DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm a");
    String landing = arrivalDate.format(format);
    System.out.printf("Arriving at : %s %n", landing);
 } catch (DateTimeException ex) {
    System.out.printf("%s can't be formatted!%n", arrivalDate);
    ex.printStackTrace();
}