ArrayList和Arrays.ArrayList的区别

1.Arrays.asList返回的是一个List的实现,但不是ArrayList,刚好和java.utils.ArrayList重名而已(吐槽1)

2.Arrays.ArrayList是一个不可修改长度(fix-length)的List,所以既不支持add也不支持remove,如果使用会抛出UnsupportedOperationException

 

建议:

除了自己明确的是ArrayList,对于第三方库返回的List接口,一律当作fix-length对待,避免不符合直觉的操作

 

另外:

大部分情况下..List使用上都是按照appendable来使用的…..(大家都这么用,所以认为都是正确的),这么看来Java以前的库对于接口的设想不太对

 

至少我认为,一个类满足一个接口必然每个接口都必须要操作意义,比如List.add就是声明代表实现类一定要实现这个接口,而不是简单的遇到没有实现的操作就抛出一个运行时异常,明显违反接口单一功能原则

(可添加,添加),我宁愿使用时候就能清楚的明白这是个NotAppendable的对象

 

多态的实现优劣/Go/Java

Go:从语法层面不是一个完备的OO语言,其实现多态用了类似this指针的做法,模拟了OO

Java:完备的OO语法,类是一等公民(java8之后default开始略扭转了趋势)

 

差异:因为OO的完备性需要包含对象与对象之间的关系,所以在JAVA编程中经常蛋疼在对象多态的海洋中(C++更惨)

Go把类之间的关系简化了,只有关系,没有所谓的继承.抛弃了需要大量思考压力的继承体系,Go中的面向对象编程实质上得到了简化(代码上没有…其实完备的OOP在设计上就必须关注…只不过写成代码之后只需要关注是否有关系就好了)

修改:

1.知乎上看到一个观点说的挺不错的,多态等是为了解决归一性,通过归一性来应对可能的修改,也就是抽象

用Golang实现OO编程

package simpleBlog

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

type BlogOperations interface {
	Persistence()
	Delete()
}
type Blog struct {
	Author  string
	Header  string
	Content string
}

func (blog *Blog) Persistence() {
	result, err := DB.Exec("INSERT INTO blog.blog (author, header, content)VALUES (?,?,?)", blog.Author, blog.Header, blog.Content)
	if nil != err {
		fmt.Println(result, err)
	}
	fmt.Println("persistence", blog)
}
func (blog *Blog) Delete() {
	DB.Exec("DELETE FROM blog.blog WHERE header=?", blog.Header)
	fmt.Println("delete", blog)
}

OO三要素:类=数据+方法

后来想想C也能实现OO编程

只要相应的函数传入一个struct的指针….

后来又想想…Python不就是这么实现的么…有一个内置的this指针(虽然觉得是奇技淫巧…)

这么看来C也能实现OO编程,技巧在于传入一个隐式指针指向一个数据结构

那么再回想一下OO三要素,类=数据+方法

也就是通过this/struct指针来实现数据和方法的关联

高性能服务端一般解决方案

1.避免锁

1.1 预分配,外部不允许修改内部状态等

2.避免IO

3.异步化

4.数据落地尽可能批量化

 

另外,从应用建模时候尽可能让数据维护本身自己,而非外部系统修改(可以天然的并行化,而不需要考虑锁),具体来说DDD,ACTOR等等都是这种思想.

在一个理想状态下,不考虑跨语言的情况下,每个对象只能由自身维护其数据的情况下,那么扩展性能够达到最大,因为完全避免的锁

消息队列设计

自行设计消息队列

需求描述

  1. 能够存储消息
  2. 能够获取消息
  3. 能够区分topic

接口设计

时序图

消息入队:

消息出队:

拓展点:

完全依赖Storage作为拓展点,若是单机消息队列,则直接实现单机Storage

若是集群存储则实现集群Storage

若是分布式存储则实现分布式的Storage

所有上层操作依赖Storage接口

已经默认实现了的单机Storage

分别是CompressFileStorage, SplitFileStorage

分别实现场景是,单消息单文件存储

多消息单文件存储

Github地址:

https://github.com/michaelssss/MyQueue

DDD(领域驱动设计)

1.确定领域界限(通常由领域专家和架构师共同确定)

2.抽象领域的套路,就是通过和领域专家交流,确定出在当前领域下的各种套路

Example:

以软件发布作为一个领域来陈述:

首先确定,当前业务界限(已开发完毕,通过测试,需要在某个商城或者平台上架)

接下来,涉及,当前商店的适配(Adapter),提交审核(Commit,Audit),最后是上架(sell granted/publish)

以上作为最基本的讨论术语。而这些专业名词,也就是俗称的套路。

3.通过动态验证模型是否满足需求,否则转2。

不断的重复交流并验证,最终得出一个模型。(类似于软件开发中的迭代,这里是模型的迭代,而非软件的迭代,但模型的迭代能够深层次的影响软件的迭代)

只要模型抽象的足够好,面向对象中的SOLID原则会自然而然的呈现,而非刻意而为。

领导力

其实扯这个话题是因为今天开会的时候我生气了,我其实真的很生气,还得笑着对人

第一点,作为一个领导,下属在任务进度迟缓的时候不应该是发脾气;

第二点,项目延迟也是作为领导拍板说用新技术带来的必然的结果;

第三点,作为一个开发,很清楚东西不是说加班赶进度就能出来的,加班能解决的,只能是设计好的东西。做到一半发现以前承诺的实现都是作废的,需求已经变更的很厉害。必然项目是会延期的。

 

 

 

 

领导力说穿了,不是说一个人对一个领域钻研的深了就自然而然的可以成为这个领域的领导人。

“领导”本身就是一个领域。这无关乎你对所在行业的钻研深度,而关乎待人接物的习惯。

其实这次让我回想起我在华为赶进度的时候。

我们当时真的就是项目定死了什么时候提测试就是什么时候提测试,每个人都有自己的工作,而刚好我手头上的任务的需求是从项目开始就在变更。

我在提测的前一天晚上都还在改需求(用户操作历史纪录)代码。其实我当时是真的非常紧张了的,当时也没有说平静的心态来写代码,这导致了,修了一个bug然后冒出另一个bug。

但是我的团队很给力,当他们手头上的事情忙完了,都过来帮我梳理需求,编写用例。经常负责事物类的兄弟还独立整理好用例表格,一起把所有事项确定下来。就算是我的直属领导也没有说发脾气什么的,也是说在人力上倾斜多一点到我这来。到了十一二点还和我一起打车一起回家。

我一直很感激我在华为这段经历,真心学到了很多东西,像项目管理的习惯,做事的方式,尽管我因为住的地方离华为实在是太远而且不方便搬家,才换到了新公司,我依然很是怀念这段日子。

 

软件开发的领导说穿了是什么:

1.项目的发起者;

2.项目进度的管理者;

3.项目的背锅者;

4.必要时候是软件开发的参与者。

起码我认为读过《极客与团队》这本书的人都能多多少少懂的点领导者的艺术。

从一个比赛题目来看业务设计应该如何设计

从一个比赛题目来看业务设计应该如何设计

先说,数据库设计如下

D:\msg\602254985\Image\Group\Image2\D]6[ZU2KJ27UP8WFNDFZR8L.png

题目:

要求设计一个接口getBlogList(userid,int begin,int offset)

返回blog以下数据

{

“Blog”:[

“blogid”:xxx, //博客id

“createtime”:xxx, //博客创建时间,需最新的在最前羰

“readflag”:1/0, //当前用户的已读状态

“praiselist”:[“xxx”,”yyyy”,”zzz”,……], //当前博客的点赞人例表

“commentlist”:[“xxx”,”yyy”,”zzz”,……] //当前博客的评论人例表

]

“Blog”:[

“blogid”:xxx,

“createtime”:xxx,

“readflag”:1/0,

“praiselist”:[“xxx”,”yyyy”,”zzz”,……],

“commentlist”:[“xxx”,”yyy”,”zzz”,……]

]

……

}

模拟数据数量级为百万级别

让我们来看看再不考虑内存占用下的最优解:

所有表预存至本地内存

提前对所有数据做好计算,到时候单纯的根据bloguid就可以在N(1)的时间下拿到数据和对象

十条数据

耗时1ms

输出压缩json大小23KB

两百条数据

耗时16ms

输出压缩json大小485KB

接下来把点赞详情和阅读详情操作给去除

十条数据:

耗时低于ms级别

输出json压缩大小低于kb级别

两百条数据:

耗时2ms

输出压缩json大小11KB

接下来把点赞数和阅读数加入操作中

十条数据:

耗时1ms

输出压缩json大小低于KB数量级

两百条数据

耗时10ms

输出压缩json大小17KB

问题在于,现实系统中,博文数量及点赞数一般的比这些模拟数据要大得多,且不可能完全load进内存中.

在上面的最优解中,瓶颈在于输出的数据量,也就是网络IO瓶颈

单次map是内存操作,一般是ns级别

网络通信的的时间一般是ms级别

彼此相差三个数量级,那么可以猜想,无论如何优化系统的响应时间也应该与这次测试相差三个数量级甚至更多.

那么以上题目放在实际系统场景中问题是什么呢?

  1. 每次请求时候才去做数据的计算统计排序(因为不允许preload就不允许启动的时候计算完毕并启用)
  2. 单次请求的数据没有区分重点和无关紧要点(你看个列表为啥要详情),导致单次查询数据量爆炸,不仅是查询的量过多,而且输出的量也是继续攀升,导致网络IO负担明显

 

针对以上,从业务上应该做如下规避:

  1. 输出列表时候不应该把点赞和评论的详情带上,而应该只需要统计量,减少输出结果的
  2. 单独维护一个列表,用于排序条件,比较使用<K.V>系统避免在业务代码中动态的进行计算(减少每次请求的遍历时间);
  3. 如点赞数和评论数也可以维护在<K.V>系统内,数据库只是一个序列化的仓库
  4. 只有用户需要查看点赞详情和评论详情的时候才去请求查询

契约式编程

DbC的核心思想是对软件系统中的元素之间相互合作以及“责任”与“义务”的比喻。这种比喻从商业活动中“客户”与“供应商”达成“契约”而得来。例如:
供应商必须提供某种产品(责任),并且他有权期望客户已经付款(权利)。
客户必须付款(责任),并且有权得到产品(权利)。
契约双方必须履行那些对所有契约都有效的责任,如法律和规定等。
同样的,如果在面向对象程序设计中一个类的函数提供了某种功能,那么它要:
期望所有调用它的客户模块都保证一定的进入条件:这就是函数的先验条件—客户的义务和供应商的权利,这样它就不用去处理不满足先验条件的情况。
保证退出时给出特定的属性:这就是函数的后验条件—供应商的义务,显然也是客户的权利。
在进入时假定,并在退出时保持一些特定的属性:不变式。
契约就是这些权利和义务的正式形式。我们可以用“三个问题”来总结DbC,并且作为设计者要经常问:
它期望的是什么?
它要保证的是什么?
它要保持的是什么?
很多编程语言都有对这种断言的支持。然而DbC认为这些契约对于软件的正确性至关重要,它们应当是设计过程的一部分。实际上,DbC提倡首先写断言。
契约的概念扩展到了方法/过程的级别。对于一个方法的契约通常包含下面这些信息:
可接受和不可接受的值或类型,以及它们的含义
返回的值或类型,以及它们的含义
可能出现的错误以及异常情况的值和类型,以及它们的含义
副作用
先验条件
后验条件
不变式
(不太常见)性能上的保证,如所用的时间和空间
继承中的子类型可以弱化先验条件(但不可以加强它们),并且可以加强后验条件和不变式(但不能弱化它们)。这些原则很接近Liskov代换原则。
所有类之间的关系就是客户与供应商的关系。一个客户在调用供应商的功能时有义务不去违反供应商所需的状态。相应的,供应商也有义务为客户提供它所需的状态和数据。例如,供应商的delete功能要求客户在data buffer当中有数据存在。相应的,供应商要保证当delete功能完成后,data buffer中的数据已被删除。其它的设计契约还有不变式。不变式保证类的状态在任何功能被执行后都保持在一个可接受的状态。
当使用契约时,供应商不应对契约条件是否被满足进行校验。大体的思想是,利用契约条件校验为保护网,在契约被违反的情况下代码要“死翘翘”(fail hard)。DbC的“死翘翘”概念让对契约行为的调试变简单,因为每个过程的行为意图被定义得很清楚。它和一种叫作defensive programming的方法明显不同,在那种方法里,供应商要负责解决先验条件不满足的情况。相对通常的情况下,在DbC和defensive programming中,如果客户违反了先验条件供应商都会抛出异常—由客户来负责解决这种情况。DbC让供应商的工作更简单。
DbC同时也定义了软件模块的正确性条件:
如果对一个供应商的调用之前类的不变式和先验条件是真,那么在调用后不变式和后验条件也为真。
当调用供应商时,软件模块应保证不违反供应商的先验条件。
因为契约条件在程序运行中不应被违反,它们可以只作为调试代码,或者在发布版本中被移除从而得到更好的性能。
DbC也能帮助代码重用,因为每段代码的契约都被很好的文档化了。模块的契约可以被当做软件文档来 描述模块的行为。

——————-from Wikipedia

为啥要抄这个呢,因为我司比较蠢…接口的字段都是变化的…..