引子

很多朋友可能会因为自己做的工作不是特别核心或者业务简单而引起面试中没有自信。但是很多公司面试的时候是可以接受面试者之前岗位的并发量、交易量低一些的。比如我们要招聘和我们交易量同等级或者以上的出来的人才,业界本来就没有多少,但我们还是要招人的。所以很多时候更偏向于考察面试者的设计底蕴、思考和解决问题的能力。

我建议面试时,面试者要争取主动权,主动引导面试。一般作为面试官也很乐意被面试者引导。因为面试官的职责是发现面试者的技术特长,为此我们绞尽脑汁的从简历中、自我介绍中去发掘。如果面试者可以自己有完整清晰的思路,是面试官求之不得的事情。

假设我是一个面试者,近几年做的都是XX后台管理系统。后台管理系统嘛,没有高并发、没有高可用需求、没有复杂架构,属于三无系统。要是我的话,会把自己的以下知识技能放到项目介绍里展示给面试官:

  • 可测试性设计

    • 谦卑对象模式

    • RESTful风格

  • 领域驱动设计DDD

    • 充血模型

    • CQRS

可测试性设计

谦卑对象模式

作为一个后台管理系统,一般场景下微服务化的价值不大。DDD领域驱动设计这种专门用于复杂问题的解决办法在这里多半也是杀鸡用牛刀。后面会讲到一些DDD技巧还是可以用的。实际中大多是采用前后端分离的架构,这种架构实践一方面是动静分离,便于缓存优化等性能考虑,另一方面也是一个出于可测试性的考虑。分离出可自动化测试的接口层和测试难度高的展现层。

展现层对象等测试难度高的对象在整洁架构中被称为谦卑对象。通过拆分不同的类或者模块,来区分容易测试的行为和不容易测试的行为,这种设计上的隔离模式被称为谦卑对象模型。

现在的很多设计对程序的可测试性提供了友好的改进和支持。比如:程序调用数据库执行操作,mybatis等持久层框架将把sql以接口的形式对外提供服务,接口有成熟的工具来做mock打桩,这是比较典型的谦卑对象模式。

另外一个比较典型的比较典型的谦卑对象模式是feign。netflix的feign把原本需要手写的httpClient(或者OKHttp)代码使用接口调用的的形式,实现了命令式到声明式的转换。同时,谦卑对象和非谦卑对象之间有很好的隔离层,也对测试更友好。对feign想做进一步了解的可参考我之前的文章《Java&Spring过时的经典语录》,这里简单举个例子:

public interface TestHttpService {

    @RequestLine("GET /xxxx?appkey={appkey}&ips={ip}&username={username}&operator={operator}")
Response getTest(@Param(value = "appkey") String appkey,
@Param(value = "ip") String ip,
@Param(value = "username") String username,
@Param(value = "operator") String operator);

}

RESTful

说起后台管理系统的接口层,RESTful风格的接口是比较流行的最佳实践。虽然这个被提了很多年了,实际严格按照这种风格设计的接口并不多。大多数系统的接口风格像是跟着江南七怪学武的郭靖一般,武功路数驳杂不成体系。

来做个判断题:

下面的代码,类上用了RestController的注解,这是RESTful风格的代码吗?

@RestController
public class JacksonController {
@Resource
private User user;
@GetMapping("/writeStringAsString")
public String writeStringAsString(String toWrite) throws Exception {
System.out.println(user.getAge());
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(toWrite);

}

}

REST(英文:Representational State Transfer,简称REST) 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。

理论上REST架构风格并不是绑定在HTTP上,但是REST本身受Web技术的影响很深, 目前HTTP是唯一与REST相关的实例。
咱们来看看需要满足哪些约束条件和原则。

资源设计规则:

1>不用大写;
2>用中杠-不用下杠_;
3>用名词不用动词;
4>URI中的名词表示资源集合,使用复数形式。

动作设计规则:

1>GET(SELECT):从服务器取出资源(一项或多项)。

2>POST(CREATE):在服务器新建一个资源。

3>PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

4>PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

5>DELETE(DELETE):从服务器删除资源。

返回结果规则:

与HTTP协议标准基本没有新的约束。要注意content-type的accept,包含accept-encoding。之前出个我在测试环境出个一个问题,我们自动化测试回归平台不支持gzip,但是请求时带了gzip,其实平台并不支持导致乱码。

通过上面的约束条件和原则咱们来总结一下为什么叫REST:"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

如果大家都理解,那上面判断题的答案也呼之欲出了:因为不满足相应的约束条件和原则,所以不是RESTful风格。@RestController 只是让资源返回结果是RESTful风格的。但不管是不是RESTful风格,都是URI。统一资源标识符(Uniform Resource Identifier,URI)是一个用于标识某一互联网资源名称的字符串。 只要定位到资源了,都是URI。

领域驱动设计DDD

充血模型

贫血模型是指实体对象或者说是POJO只包含简单的set、get方法,充血模型认为一个对象是拥有状态和行为的。什么叫状态和行为呢?举个例子:

@Setter
@Getter
@ToString
@EqualsAndHashCode
public class Pojo {
private String name ;
private String status;
public int getStatus() {
return NumberUtils.toInt(status);
}
}

上面类代码上用了lombok的@Setter、@Getter注解之外,还用了@ToString、@EqualsAndHashCode,这两个虽然是Object对象的基本方法,实际上也是做了状态和行为的事情,而不只是@Setter、@Getter的数据存取。与之类似的还有上面的int getStatus,实际上进行了类型转换这个行为。

现在针对到底使用贫血模型还是充血模型更好说法不一。我个人更倾向于使用充血模型,因为这种方法从领域上更内聚。但是很多人不建议使用,主要是因为充血模型对个人能力有更高的要求。充血模型开发者需要自己去识别哪些是实体领域中的。对于一般的spring开发者来说,个人经验上有个简单的办法:凡是要引用@Service、@Component的都不要放到里面,之前本来要放到XXUtils的建议看看更符合哪个实体领域,不要一股脑放到util包下面,看看是否可以划分到实体领域中。

CQRS

CQRS — Command Query Responsibility Segregation,顾名思义是将 command 与 query 分离的一种模式。CQRS 将系统中的操作分为两类,即「命令」(Command) 与「查询」(Query)。命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。而查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。

在后台系统中,某些查询操作可能会过于频繁,比如页面定时刷新获取数据。这些查询操作不需要保证每次都成功。而命令操作如果失败则涉及到事务回滚等操作,需要保证操作的成功率。这时候可以使用CQRS隔离,比如将检查流量和命令流量使用hystrix隔离,架构清晰了,还可以画出下面这样清晰的架构图:

总结

上面都是后台管理系统中常用的一些技术,其实还有ACL(防腐层),批量操作的隔离、熔断、分片,数据异步转同步等限于篇幅这里就不介绍了。只要面试中能够引导面试官提问这方面的技术并且可以讲的明明白白,已经可以超过大部分的面试者。

推荐阅读

服务设计要解决的问题

分布式存储系统的一致性-可见性差异

代码荣辱观-以运用风格为荣,以随意编码为耻

程序员如何破局前行

CURD系统怎么做出技术含量--怎样引导面试的更多相关文章

  1. CURD系统怎么做出技术含量惊艳面试官

    在<CURD系统怎么做出技术含量--怎样引导面试>有朋友开玩笑说都用上了领域驱动了,就不叫CURD系统了吧.这里我解释一下,怕大家对DDD领域驱动设计有什么误解. DDD是为解决软件复杂性 ...

  2. C#工业物联网和集成系统解决方案的技术路线(数据源、数据采集、数据上传与接收、ActiveMQ、Mongodb、WebApi、手机App)

    目       录 工业物联网和集成系统解决方案的技术路线... 1 前言... 1 第一章           系统架构... 3 1.1           硬件构架图... 3 1.2      ...

  3. 谈“技术含量”的问题

    最近又从离职同事那里听到这样的抱怨(原因),说做的事没有技术含量.想一想,从事车载软件开发这个行业快8年了,这个话题似乎从来没有停过.我自己曾经也为自己做的事是否有技术含量而苦恼过,今天就专门花点时间 ...

  4. 装多系统删除某个系统后,如何恢复ubuntu引导

    在重装系统或者再装多个系统后可能会出现ubuntu的引导文件不存在的情况,windows系列的引导文件可以用winpe修复,但是ubuntu就不可以,虽然网上很多种修复ubuntu的引导文件 方式,但 ...

  5. 没什么技术含量的Remove Before Flight

    航空业有很多值得我们借鉴和学习的工作方式,将来有时间我会给大家引荐更多实例. 仔细观察每架停泊着的飞机,会发现机身很多地方都挂着细长的红布条,上面写着"REMOVE BEFORE FLIGH ...

  6. Java开源生鲜电商平台-系统架构与技术选型(源码可下载)

    Java开源生鲜电商平台-系统架构与技术选型(源码可下载) 1.  硬件环境 公司服务器 2.   软件环境 2.1  操作系统 Linux CentOS 6.8系列 2.2 反向代理/web服务器 ...

  7. Linux系统在启动过程中grub引导文件丢失的解决方法

    在/boot/grub2目录下有一个grub.cfg文件:该文件主要是用来自动地引导系统启动内核程序和系统的初始化程序. 问题一:当系统在启动的情况下,我们不小心删除/boot/grub2/grub. ...

  8. CODING 受邀参与 DevOps 标准体系之系统和工具&技术运营标准技术专家研讨会

    2019 年 5 月 24-25 日,国内领先的一站式 DevOps 解决方案供应商 CODING 作为腾讯云的深度合作伙伴,受邀参加在成都举行的由 TC608 云计算标准和开源推进委员会主办,中国信 ...

  9. 前端 & 技术团队 TL & 如何面试 & 如何带人

    前端 & 技术团队 TL & 如何面试 & 如何带人 面试 带人 作为 TL,深度了解你的团队非常重要,要去了解每个人的想法是什么,他的诉求是什么,他目前的状态怎么样,以及对他 ...

随机推荐

  1. win10系统git的安装与使用命令

    一.git简介 git是一个开源的分布式版本控制系统,可以高效的进行项目版本管理.分布式相比集中式最大的区别在于:分布式开发者可以提交到本地,每个开发者通过克隆在本地机器上拷贝一个完整的git仓库. ...

  2. Windows 10 64位操作系统 下安装、启动测试python pycharm

    一.下载python3.7.7安装包 1:详细下载安装版本可见官网:https://www.python.org/downloads/release/python-373/ 2:百度盘分享连接:htt ...

  3. P3426-[POI2005]SZA-Template【KMP】

    正题 题目链接:https://www.luogu.com.cn/problem/P3426 题目大意 给出一个长度为\(n\)的字符串\(s\),求一个长度最小的字符串\(t\)使得\(s\)所有\ ...

  4. 4.自定义类加载器实现及在tomcat中的应用

    了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器 一. 回顾类加载器的原理 还是这张图,类加载器的入口是c++调用java代码创建了J ...

  5. Node.js躬行记(12)——BFF

    BFF字面意思是服务于前端的后端,我的理解就是数据聚合层.我们组在维护一个后台管理系统,会频繁的与数据库交互. 过去为了增删改查会写大量的对应接口,并且还需要在Model.Service.Router ...

  6. 【k8s】使用k8s部署一个简单的nginx服务

    名词解释 Namespace 表示命名空间 Deployment 表示pod发布 Service 表示多个pod做为一组的集合对外通过服务的表示 kubectl 是k8s的命令行操作命令,可以创建和更 ...

  7. 【Docker】(9)---每天5分钟玩转 Docker 容器技术之镜像

    镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器.为什么我们要讨论镜像的内部结构? 如果只是使用镜像,当然不需要了解,直接通过 docker 命令下载和运行就可以了. 但如 ...

  8. Jave Hbase AP

    Hbase API 类和数据模型的对应关系 HBaseAdmin 类:org.apache.hadoop.hbase.client.HBaseAdmin 作用:提供了一个接口来管理 HBase 数据库 ...

  9. 题解 GRE Words Revenge

    题目传送门 题目大意 给出 \(m\) 次操作,分别为以下两种操作: 学习一个单词 给出一个段落,查询里面有多少个学过的单词.注意,如果学习过 \(\text{ab,bc}\) ,当前查询段落为 \( ...

  10. Miller Rabin 详解 && 小清新数学题题解

    在做这道题之前,我们首先来尝试签到题. 签到题 我们定义一个函数:\(qiandao(x)\) 为小于等于 x 的数中与 x 不互质的数的个数.要求 \(\sum\limits _{i=l}^r qi ...