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

 

持久化

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

缓存层

从技术上考虑,该系统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得到需求所描述的模型了,其中以下几个需求完全是基于上述模型可以直接扩展:

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

最终得到以下类图

第三方应用接入平台需求

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

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

如何问问题

Q:为什么提出这个问题

A:每次面试的时候总是面试官提问题,应聘人回答,但是回答完之后却又发现其实觉得自己没有真正回答任何一个问题,我想通过这个问题,复盘一下我面试时候出现的问题。

Q:所以应该怎么问问题呢?

A:首先先区分这个是不是有效问题,

怎么定义有效问题这个词语呢,我举个简单的例子:

如何对10W的数据进行排序;(这是一个无效的问题)

如何对10W的冷数据进行排序;(这个开始缩小范围了)

如何对10W的冷数据在获取的时候排序(继续缩小范围)

如何对10W的冷数据在获取的时候得到前100位的数据;(范围继续缩小)

如何对10W的冷数据在获取的时候按照数据存放的时间获取最近的100条(这算一个有效问题了)

所以,我们如何定义一个问题是有效问题,即是:能够很清晰简单的回答的问题,比如对10W的数据排序一上来提问,是个人都会是懵的,除非他在日常工作中曾经遇到过相同情景的事情,那他回答的一定会是他的那个分支的问题。

Q:那我们遇到面试官提问的时候如何能够得到真正的问题

A:像平时和产品或者需求提出者那样交流。首先我们应当根据问题确定提问的上下文,比如,还是以上面排序的例子作为示范:

我和产品或者BA会这么沟通:

  • 我要对这10W条数据倒序输出
  • 你这是什么样的使用场景呢
  • 这样的,我需要展示用户的最近几条操作记录以供恢复账号使用,是给运营人员用的
  • 哦,那事实上你只需要最近的操作记录是吧?你大约需要展示多少条呢?
  • 100条
  • 那就是按照时间排序,把最近的100条操作记录返回给页面是吧?
  • 这些数据在业务上来说用户是无法串改的把?
  • 运营方也不许篡改啊
  • 也就是这是这些数据其实是固化了的?
  • 那整个就变成了,我要从10W条固化数据提取出按照操作时间得到最近100条操作一记录并返回给运营人员(得到完整需求)

那么,作为开发,我就会选择在存储的时候用一个Buket存储最近100条数据,然后多个Buket组成一条直链并按照时间严格做排序

查询或者取数据的时候,则只要沿着buket一直扫描或者直接由时间计算得到位置即可。

Q:但有时候提的问题例如:介绍一下SpringMVC是如何工作的

A:这个其实并没有在问问题,这是在考察背书能力毕竟清楚SpringMVC是如何工作的表明,我应该是这个领域的专家。而事实上大部分工作的码农依赖的是HTTP协议中的一些特定部分而非SpringMVC这么一个特定框架下的领域知识。遇到这样的面试或者说面试过程中大部分都是这种问题的话,要考虑下是否还要去这样的公司,毕竟能问出这种问题的公司要么整天是修业务BUG,要么是对SpringMVC这种框架做过hacker使用的公司,哪种日子都不会好过。

Q:所以面试前应该有什么准备工作呢?

A:面试前其实没什么准备工作,面试最主要的是让求职者和公司之间进行交流。不要把面试想象的太过于像考试,而不是交流,心态变化了,那么行动上就会自然的出现变化。

前K项问题

其实吧,这个问题问出来是没有答案的,因为在实际业务中会有很多种使用场景,我们需要按场景来分类才能得到真正的问题

必须要服务端全局有序的

数据量小的时候,直接快排

数据量较大时候,对数据做分段,然后归并排序

不需要服务端全局有序的

数据直接交付client处理排序

而client有区分是否是强力PC使用还是弱计算能力的计算设备

 

除了以上,还要区分,要求一直有序还是说,最后输出的时候有序,还是说其他需求

以面试时候提到的跳一跳排名来说,其实根本没有服务端排序这个事情,小程序获取成绩应该是三个步骤:

  1. 获取用户列表中已开通跳一跳的用户
  2. 获取步骤1中所有user的成绩
  3. 对成绩按大小倒序排

就会发现和前K大这个问题没有任何关联。。。

总的来说。。我发现面试的数据结构题目对于强人和应试型人才很有优势。。but,我这种经常是时候脑袋一转发现不对的人来说是很难的。。。毕竟我的注意力也不在这里面。。

假装读懂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语句

2017总结

2017总结

时间线

一月份:还在华为忙活用户关键动作信息记录的系统

二月份:对接了OSS存储

三月份:接收到深圳市理才网的工作邀请,面试之后觉得公司还不错,工作氛围好,福利也不错。

四月份:正式入职深圳理才网

五月份:接手理才网应用市场

六月份:预研理才网应用开放平台

七月份到十二月份:理才网应用开放平台研发

十二月份:理才网融资困难,我这边就离职了

感想

  • 其实大部分情况下,外包是可以去的,但是一定要了解清楚外包到什么平台去,具体项目组很重要,外包到腾讯阿里华为百度等公司其实这个工作经历也是能吸引很多HR的目光的
  • 软件研发中,写代码真的是最不重要的一个步骤,更关键的是业务的设计,越来越讨厌一部分人的如下这些话:“不就是加个数据库字段嘛”,“不就是多展示一个页面嘛”,很大程度上这些需求的出现都是设计阶段的不合理。
  • 一定要业务代码和SQL分离,否则你只是在用业务代码写SQL SCRIPT
  • 在理才网的时候,同组的有位同事是曾经自己创业的,给我们还做了次分享教我们如何分辨一家公司是否真的有前途,真的觉得所谓技术就不一定是一个开发人员的所有。作为一个公司的员工,更重要的是学会分析你到底做了什么,你做的事情意义何在,代码更多是实现你做事情的手段。

自用动态dns(Server/Client)

断断续续的做了一个月(主要是懒)

完成了

Server负责接受并返回Client的公网IP

Client负责定时轮询Server并在IP更新至阿里的DNS服务器

Client

Sever

在client和Sever,go build main.go

client的启动参数分别为 accessKey accessId severAccessKey severIP:port

server启动参数为

severAccessKey

下一步将domain和RR放在配置文件中