近期总结

近期总结

问题

  1. 每个人都感觉自己非常忙却产出非常的少
  2. 从我这个角度观察,每天有大量的废话时间,尽管废话时间是与客户交流的
  3. 主管人员缺少决断却没有人能够站出来说背起责任
  4. 我仍然是缺少项目管理经验,同时还有分出时间来分析任务和分派任务至开发人员

问题的分析

  1. 从产出少的角度举个例子
    首先是我们的需求没有人做管理,每个人都围着需求说明书在转圈,没有一个富有项目管理经验的人能够明确的说,好的,我们这个文档做到这里,可以了,更多的情况是,你们这个文档不行啊,太不丰满,继续去摘要输入输出流程描述,不然对不起那几百万的钱。
    以上事实得出一个结论是,缺少文档管理及写作方面的人才
  2. 每个人都感觉自己非常忙
    这个的问题是我们前期参与项目的几个人,对着同一个文档,各自不同的部分,做了非常多的重复工作,举个例子是,客户的商品管理,前后出了十个版本,没有一个版本是和客户核对过的。
    这个问题的结论是,在缺乏项目管理经验的状态下,对于项目进度及内容的失控
  3. 废话时间这个问题
    废话指的是什么呢,是客户自己无意识中在发散,但是我们这边需求调研人员没有抓住自己的工作主要目的,亦即确认客户需求,客户天花乱坠的吹,我们静静的旁边听,或者是在旁边,嗯,是的,好的,没问题,您听我解释,而正常的情况应该是,大家针对目前的目标,针对性的,比如说630我们只要A需求落地上线,而A中需要拆分成几个不同的过程或者是需求,主导权应该要在我们开发系统的人手上。
    这个问题的结论是,主导项目管理开发的人员缺少决断,并且没有意识到整个项目的拖延是因为自己的没有决断导致的
  4. 缺少决断,没人背起责任,这就很清晰了,我在项目开展的第三周,反复提出,已有的不成熟的文档也最好能尽快和客户对接,通过客户的帮助来完成我们的文档,我的提议不一定是好的方案,但是却被很粗暴的驳回(三次),同组另一个同事也曾提出和我一样的意见,驳回的理由很苍白,我的做法是互联网做法,在我们公司不成立的,不能这样搞,在项目依旧进展缓慢的情况下,我其实也已经心灰意冷了,正常来说,在事情出了风险的情况下,只要能推进项目进度的做法都应该是可取的
    这个问题,我认为是领导在制度缺失的情况下,在压力下做出了不正确的做法,他在沿用了他曾经经历过的安全的做法
  5. 缺少项目管理经验,这个责任在我,我在这一个月内没有成长起来,例如CMMI实践操作文档我也是最近一周才去看

我提出的解决方案

  1. 从总公司抽调两个具有专门技能的人才
    1. 具有丰富的项目管理经验的人一名
    2. 具有现有框架开发及设计经验的人一名
  2. 需要以上人员扮演保姆或者是老师的角色
  3. 需要有个人提出来,出错在我,你们放心干

技术无关

有意思的一点是,其实是每个人看起来差异不大,但是人与人通过语言交流真的特费劲,有的人喜欢做什么事情都要先解释一番,有的人很急躁。
抓住一个主要矛盾是,在项目尽可能的规范下,尽可能的快速推进事物。
每个人的立场不同关注点不同,心平气和,放平心态

从需求到代码落地

业务需求分析

1.     调研需求宿主的原有业务

2.     调研需求宿主的诉求

3.     调研需求宿主是否由清晰的规划

业务分析阶段

1.     协助需求宿主梳理原有业务

2.     协助需求宿主新增业务

3.     协助宿主将新增和原有业务合并梳理并确立开发任务

业务需求转化开发需求

待完成

 

首先的首先

调研客户的现状,输出产物,现有流程图+要素表

然后要反复与客户确认流程图是否与客户达成了公式

接着才是将现有流程+客户诉求分解成功能点~!!!!!!!!!!!!!

如何让软件插件化

如何让软件插件化

软件的插件化,核心是对软件进行抽象,达到一种程度使得所有人根据你抽象的模型编写完代码后能够顺利在核心软件开发者未知情况下直接使用。

很现成的例子是我们常用的插座:

目标:提供电力

如何使用:将电缆接入插座(plug-in/plug-out)

具体实现类:满足中国国标三口插座/两口插座

我们再以Spring启动事件为例,看一下Spring是如何实现的

Spring-Context初始化时候以以下函数为重点Application.refresh()

其中Fresh消息发布地方在FinishRefresh(),

在publishEvent中就能看到到底Spring是如何将其插件化的了:

重点在于需要现在把监听的对象通过spring ioc进行管理,然后就可以简单的通过订阅者模式进行事件的的发布。

划重点:

重点在于发布一个规范让所有人进行遵守,规范越是简单,那么就越灵活,越是复杂越是只能支持特定事物。

如Spring的需要两个要求,一个是对象需要通过Spring来管理并且需要实现一个特定接口。

所以另一个问题就是,如何得到规范,那就是考验设计者心智的情景了。

第三方接入平台需求建模(二)

 

持久化

考虑到我们的系统是不稳定的,内存一定不充足的,故而我们要进行持久化,以下是完成持久化类的类图:

缓存层

从技术上考虑,该系统Query的请求会占到绝大多数,且并发数量会高,如果只有DB那么压力会单点压在数据库读上,故而对Query请求增加缓存层,同时考虑到部署的机器会有多台,还要使得多台机器上缓存一致性。

我这边是使用了Redis作为集群通信的中心,完成了一个本地存储的类不便展示,思路是将最近刷新应用信息的时间放在Redis上,只要节点当前的时间比redis的时间新或者相同则不处理,否则重新从数据库中拉去数据

为了简便,没有单独的建立cache的package,只是单纯的在持久层增加了一个ClusterMap,持久化类直接使用

为什么将第三方接入的文档放出来

  1. 反正内容足够简单
  2. 这是我第一次用DDD+充血模型的方式对项目进行分析
  3. 这是我第一次完整的完成了整个项目的

其实这次放出来的,是我者离职了半个月之后提炼的,原有的代码其实很冗余,我刚开始建模的时候并没有说把流程,职责区分,也没有把持久化代码和业务模型本身的代码进行区分,导致了后期改动相当的难,最主要的点是有部分业务代码直接用SQL实现了,这并不是一个好习惯。

接下来还有具体实现一个函数时候的状态转换图,还有生命周期图还没有总结好。希望我不要弃坑了

第三方接入平台需求建模

对照着需求文档我们对平台进行建模

首先第一点关注到的是关键词

  1. 应用
  2. 授权
  3. 审核
  4. 开发者
  5. 企业

所以创建以下几个对象:

关注到授权是个动作,我们将auth的动作添加到几个对象上去,注意到几个auth的对象不一样,我们需要做区分,按传参区分

此时我们动态的再脑中运行一下,发现这个模型只满足了授权的需要,我们把其他需求添加进来

现在就差Application的状态跃迁由谁来负责了

按照逻辑上来讲,开发者应该知道应用开发的整个生命流程,但是由于这是在第三方平台上,有一些不可见的逻辑,我们这时候应该把Application的状态职责由Application自己负责管理所以如下:

这个时候发现,Developer和Application都自己负责了自己的生命周期的进行,所有操作只是发起了一个流程。

另外,关注到,审核的信息其实是Application的一个Snapshot而已,所以无论外界对Snapshot做了什么都不会影响到Application本身,但是要注意到,Snapshot本来不应该可以被修改,故而要有final修饰。

这时候核心的几个概念就已经可以用这个类图来表达了。

接下来就是扩展Application得到需求所描述的模型了,其中以下几个需求完全是基于上述模型可以直接扩展:

  • 有的应用需要把代码托管到平台处
  • 有的应用还需要数据库应用
  • 有的应用不需要审核只需要用户授权即可直接添加到用户的列表中

最终得到以下类图

第三方应用接入平台需求

第三方开发者接入平台需求文档

  • 开发者要先认证才能提交应用
  • 开发者认证需要提交一系列材料
  • 应用的信息能够多次修改
  • 应用的信息应该多次修改后能够被检索
  • 应用需要被审核才能被上架
  • 应用含有如下信息:
    • 应用的名称
    • 应用的图标
    • 应用的分类
    • 应用的授权码/签名
    • 应用的说明
  • 要区分已审核应用和未审核应用
  • 有的应用需要把代码托管到平台处
  • 有的应用还需要数据库应用
  • 有的应用不需要审核只需要用户授权即可直接添加到用户的列表中
  • 开发者创建一个应用时候默认需要对开发者本身做授权
  • 企业用户只有在付款并且应用成功开通之后才进行授权

假装读懂Java线程池

假装读懂Java线程池

线程池是干什么的

不用线程池则是一个任务对应一个线程,若采用线程池那么,固定数量线程可以完成超过线程池的任务数。

为什么要用线程池

每个Thread执行的任务时间可长可短可能死循环,我们假设一万个任务需要执行,其中有几个会死循环,那么可以断言,会产生内存泄漏因为线程无法释放。

如果采用线程池,第一可以减少上下文的切换提升效率,第二就算产生泄漏,也能控制损害范围不至于是整个系统崩溃

Jdk是如何实现的

Jdk将任务和线程的角色分离了,任务称为Task是一个Runnable对象(应该是为了无痛切换原有用Thread自己实现的run,不然单独建立一个Task对象会与存量代码产生割裂),完成Task的对象成为Worker,Worker就是实际工作的线程,注意这里的Task可以为任意数目,而Worker只能是有限数目。

具体流程是:

1.用户submit或者execute提交一个Task

2.查找/创建Worker并检查是否有空闲

3.将任务赋予Worker并改变Worker当前状态,增加WorkCount

4.Worker一旦将任务执行完毕且任务队列为空将当前Worker丢弃,并减少WorkCount

5.检查当前线程池是否满足最小启动线程值

6.阻塞在获取Task状态直到下一个任务队列不为空,重复流程2

当然还有其他一些细枝末节的,就不再这个主流程上展示了

为毛不画流程图

大哥。。我只能手绘。。工具不会用

如何避免将写过程式代码

如何避免将写过程式代码

这是我在写理才网的应用管理平台时候获取的教训。

我们先来看一个简单的应用提交的模型:

其中类Application是单纯的数据类,所有的业务都集中在了ApplicationService,如果这个程序没有迭代的需求当然这是一个很好很简洁的代码,但是一旦我们增添一个需求,比如我的应用是有多种类型的,某些类型做一些操作,另一些又不用,还有一部分公用的操作,我们看看上图的简单模型会变成如何:

这个时候我们会往Service的具体方法做如下处理:

If(application.getApplicationType()==type1){

//dosomething

}else if(){

//dosomething

}………………

只是增加了一个需求,代码就开始变得臃肿起来

另一种做法是什么呢我们来看看:

这种做法就是将不同类型的Application建立不同的数据类,每个数据类的Service方法都不同,这样也可以做到简单,但是不简洁,Service的膨胀依旧存在,而且比原来更加突出。最后就会变为,每种Application的类型都有一个对应的ApplicationTypeNService。不知道在阅读本文的各位有没有想过如何用C语言写出面向对象的代码。实际上就是如同最后一种方法所说,每个方法的第一个入参是一个结构体指针。

既然我们都已经采用了Java这样的面向对象语言,为何不直接利用起来呢。

我们看最后面的这个方法如何改造:

这个时候我们把公共的一些方法放在了基类Application中,不同类型的Application的特殊操作放在了其实现类中,相对于前两种方式就十分的简洁,并且实现种也极大的减少了if-else语句