天天看点

面试官:深度不够,建议回去深挖

作者:小傅哥

一、前言:为啥不要你?

​咱们这场面试完了,作为老乡我想和你多聊几句。​

从刚面试的问题回答中,能看得出你用了不少拙力背了不少题。直接拿这些技术点问,你可以回答。但同样是这些技术点,我换个场景来问用到了什么技术,你就像从没有听说过一样。当然不可否认你能通过背把这些内容记住也是一种能力,但作为招聘从事软件编程的码农来说,其实更希望是招聘那些通过实际场景积累下来技术经验研发人员,对各个技术点有张有弛,举一反三。这也是一个理科生该具备的学习编程的基本素质,也更具有培养价值。

你肯定想,那为啥明明大部分时候都是CRUD开发,怎么还那么多要求呢?招进个人能干活就行呗?

但其实能干活的人多的是,你看;同类公司间为了市场有竞争吧、公司内同部门为了业绩有竞争吧、部门内各小组为了绩效有竞争吧。那么同样一个事有的公司能做起来有的公司就不行,因为各个公司所具备的基因不同,而这个基因主要是来自公司选择的市场面和相关人才积累。那么放到各个公司部门内的小组也一样,为啥有的组就那么高绩效、那么多晋升指标、那么多加薪包。那都是这个组内除了完成基础项目一样,还有很多具有超高素质的人才,所拼出来的。再拿这些拼出来的成绩兑换成绩效分配给组员。

现在缕清了,如果招聘一个组内平均能力以下只能完成 CRUD 开发的,那么就是招聘进来分配资源包的。放到组内没有竞争力、放到部门内垫底,所以领导根本没有那么多经历培养一个社招的还需要大量时间培养的。—— 这样的培养机会只会给到应届生。

所以在你度过编程阶段的新手村阶段以后,就不要把时间只是放到背八股文,堆CRUD代码上。这些东西搞多了,会让人厌烦,吸收的不多,收获的不大。而以大部分连八股文都能背的下来的人来说,把这样的时间精力放到吸收有深度的技术项目上,同样时间下成长的会更快。

这些东西本就没有多难,难的是你不知道,从哪知道!—— 你不是学不会,你只是没有人带你开开眼界!​

​你天天泡酱缸里,你也能成咸菜!​

二、深耕:科技与狠活!

但!有这样的深耕技术的小傅哥在,我会帮你知道你不知道的,也会帮你知道你知道但没法深知的。—— 这也是我的初心,成为粉丝最受信赖和尊重的技术号主。沉淀、分享、成长,让自己和他人都能有所收获!

接下来小傅哥就给大家举一些场景案例,这也是当你缺少这些深度后,倒置你的简历那么空洞,你的回答那么苍白的主要原因。以下这些内容来自于粉丝读者的提问后小傅哥给予的回答

1. 场景设计

问题:目前在做一个微商城系统,中间有一个类似购物车结账,支持改价和使用优惠券等。目前遇到一个问题,就是优惠分为2种,一种是商品直减优惠,这种优惠我使用策略加责任链模式进行了重构优化能快速扩展。但是另一种是类似满减优惠,需要根据各个商品在总价的比例均摊给不同的商品优惠金额,这里我们使用的均摊算法是最后一个商品优惠金额等于总优惠金额-商品a-商品b的优惠金额,这样能解决1/3这种小数问题。

回答:

  1. 背景(这类分摊计算的逻辑还是蛮复杂的,虽然复杂,但这类业务还是蛮有意思的)
  • 1.1 优惠类型可能包括:直减、满减、N元购、折扣、优惠限定SKU
  • 1.2 支付方式优惠券,免息、分期百分比优惠、红包
  • 1.3 合作分摊,包括优惠费用的承担方,各自出资占比,有了出资后运营才能配置优惠券
  • 1.4 多种商品SKU组合购买 X 多种优惠组合支付 X 支付方式优惠(可选)
  • 1.5 部分商品退货,根据优惠分摊金额扣除后,退款其余部分。PS:但有时候也有业务需求是退款时候,分摊调整,所推商品金额如果能覆盖优惠券,则退回优惠券和剩余金额。如:用户支付了80元,买了5件商品,用了100-20的满减优惠券,那么1件商品退款的时候,退款了10元+20元满减券。但也有时候是支持用户选择的,比如你同意退款15元还是退款10元+20元优惠券。具体要根据合规、风控、业务三方协调确定产品方案,有时候不同年度市场规则调整,可能也会随之处理分摊方式。
  1. 设计
  • 2.1 结构上使用模板模式,因为分摊是一套标准的流程,具体分摊由不同的优惠券策略进行处理。
  • 2.2 在模板模式中抽象类可以继承数据支撑类和配置类,也可以结合策略模式、责任链模式等,便于组合使用。
  1. 流程
  • 3.1 接口中需要的核心参数包括:父单号、下单商品SKU列表、商品价格、实际支付、优惠券金额、优惠券信息。当然可能这些信息需要通过单号拆分后自己查询组合,这个时候模板模式的数据支撑类就发挥作用了。
  • 3.2 模板模式的数据处理中,为商品列表提供分摊占比计算,A/(A+B+…N) 保持占比记录。
  • 3.3 模板模式分摊方法中for循环优惠列表,在循环方法中调用抽象分摊方法。
  • 3.4 在子类实现的抽象分摊方法中,调用优惠类型分摊计算策略方式。100-20 20元按照商品分摊比例,循环计算,并填充到抽象模板中的Map<String, List<分摊对象>>中,key 是优惠ID。由于计算会有余数,这部分分摊给最后一个商品。最终形成一组各个优惠分摊到每个商品SKU的分摊结果。
  1. 数据
  • 4.1 在数据库中要记录每一条的分摊记录,商品父单、子单、金额、实付、优惠类型、占比、分摊金额等,这些方便后续进行退款以及结算给商户使用。
  • 4.2 同时要有一张总表来记录一个商品分摊后的完整信息,是哪个商品父单、使用的优惠组合,这个表有点和订单表类似,不过会填充一些分摊信息与4.1表1vn的结构。
  1. 扩展
  • 5.1 新提供的分摊优惠券了类型策略,采用数据库配置的方式处理,并在程序启动的时候,加载到分摊模板的Config中,这样就可以处理新增的分摊计算方式了。
  • 5.2 不过可能有时候实际的业务订单要比分摊系统快,那么这个时候出现的订单,不能分摊则要做归档处理,写入归档表,后续开发了新的分摊策略和配置,再开启任务扫描处理分摊。

2. 技术问题

技术问题的解决能力,需要来自于编程上的日积月累,参与更多的场景,碰到更多的问题。这样才能积累经验,为此小傅哥专门收集实际开发中所遇到的异常并进行模拟复现。让大家更好的吸收这些实战经验。

面试官:深度不够,建议回去深挖

2.1 rollback-only

  • 问题:rollback-only
  • 异常:线程执行某个定时任务,在事务提交时抛出了异常。看到rollback-only字样,这个是什么原因引起的。写代码要注意什么能避免产生这一种情况。
  • 测试:用数据库表防重做插入测试,触发异常;
  1. 两个方法都加了事务注解,两个方法都会受到到事务管理的拦截器增强,并且事务传播的方式都是 REQUIRED,当已经存在事务的时候就加入事务,没有就创建事务。这里A和B都受事务控制,并且是处于同一个事务的。
  2. A调用B,A中抓了B的异常,当B发生异常的时候,B的操作应该回滚,但是A吃了异常,A方法中没有产生异常,所以A的操作又应该提交,二者是相互矛盾的。
  3. Spring的事务关联拦截器在抓到B的异常后就会标记rollback-only为true,当A执行完准备提交后,发现rollback-only为true,也会回滚,并抛出异常告诉调用者。
  • 复现:​​https://gitcode.net/KnowledgePlanet/CodeTutorial/Bug-Code/-/blob/master/src/test/java/cn/bugstack/guide/test/RollbackOnlyTest.java​​

2.2 Deadlock

  • 问题:死锁
  • 异常:Deadlock found when trying to get lock; try restarting transaction
  • 测试:多线程模拟并发下,一个事务未提交完成,又来一个事务。
  • 复现:​​https://gitcode.net/KnowledgePlanet/CodeTutorial/Bug-Code/-/blob/master/src/test/java/cn/bugstack/guide/test/DeadlockTest.java​​

2.3 主从同步

问题:在高可用场景中,数据库会做主备,那么当主数据还没来的急同步到备数据库,主数据库挂掉了。这种场景如果是对数据一致性要求比较高的情况下,架构又该如果考虑,业务又该如何补偿呢。

  • binlog 说明;用于记录数据库执行的写入性操作,以二进制保存在磁盘。binlog 是 mysql 的逻辑日志,由 Server 层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。实际应用中,binlog 用于主从复制、数据备份。
  • binlog 分类;STATMENT、ROW、MIXED,mysql 5.7.7 之前默认格式为 STATMENT,5.7.7 之后默认为 ROW;可以通过命令查看 mysqlbinglog mysql-bin.00001 | more
  • 1 STATMENT:基于 SQL 语句复制,每一条修改SQL语句都会记录到binlog
  • 2 ROW:基于行复制
  • 3 MIXED:基于 STATMENT、ROW 的混合模式
  • 主从复制:Mysql 主从复制需要三个线程:master(binlog dump thread)、slave(I/O thread 、SQL thread)
  • 1 binlog dump线程: 主库中有数据更新时,根据设置的binlog格式,将更新的事件类型写入到主库的binlog文件中,并创建log dump线程通知slave有数据更新。当I/O线程请求日志内容时,将此时的binlog名称和当前更新的位置同时传给slave的I/O线程。
  • 2 I/O线程: 该线程会连接到master,向log dump线程请求一份指定binlog文件位置的副本,并将请求回来的binlog存到本地的relay log中。
  • 3 SQL线程: 该线程检测到relay log有更新后,会读取并在本地做redo操作,将发生在主库的事件在本地重新执行一遍,来保证主从数据同步。
  • 复制过程:
  • 1 主库写入数据并且生成binlog文件。该过程中MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。
  • 2 在事件写入二进制日志完成后,master通知存储引擎提交事务。
  • 3 从库服务器上的IO线程连接Master服务器,请求从执行binlog日志文件中的指定位置开始读取binlog至从库。
  • 4 主库接收到从库的IO线程请求后,其上复制的IO线程会根据Slave的请求信息分批读取binlog文件然后返回给从库的IO线程。
  • 5 Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。
  • 6 从库服务器的SQL线程会实时监测到本地Relay Log中新增了日志内容,然后把RelayLog中的日志翻译成SQL并且按照顺序执行SQL来更新从库的数据。
  • 7 从库在relay-log.info中记录当前应用中继日志的文件名和位置点以便下一次数据复制。
  • 降低延迟:
  • 从库上的执行,即sql_thread更新逻辑,在5.6版本之前,是只支持单线程,那么在主库并发高、TPS高时,就会出现较大的主从延迟。因此,MySQL自5.7版本后就已经支持并行复制了。可以在从服务上设置 slave_parallel_workers为一个大于0的数,然后把slave_parallel_type参数设置为LOGICAL_CLOCK
  • 降低多线程大事务并发的概率,优化业务流程
  • 优化SQL,避免慢查询,减少批量操作
  • 提高从库机器配置
  • 主从同机房、通网络、带宽、地域
  • 主从切换,日志恢复

3. 技术架构

面试官:深度不够,建议回去深挖

总有同学分不清 MVC 和 DDD 的本质区别,却又总被一些理论搞的晕头转向,听不懂:领域专家、战术战略、模型推演等,这些词让原本就模糊的概念更加模糊,根本没法落地。所以给大家画了一个 MVC 和 DDD 的对比图,便于大家可以从代码实现视角的更好的理解DDD。

MVC:更偏向与数据建模实现,由数据调用驱动,所以也就引申出的DAO、PO、VO类会随着项目开发不断的膨胀,不易于迭代和维护。

DDD:以业务流程提炼领域模型为驱动,设计和实现模块开发,在一个领域中包含mode对象、仓储数据、服务实现,也更注重设计模式的使用,否则实现的DDD徒有其表更多的只是归类了 DAO、PO、VO 对象。

所以如果想了解DDD如何落地,非常建议把DDD抽奖系统的代码好好实践起来。

4. 学习运用

问题:手撸spring、手撸MyBatis如何体现在简历上?小傅哥可以给个Demo吗

  1. 体现在专业技能上,例如;

    1.1 深入学习 Spring 核心流程模块,包括;IOC、AOP、依赖倒置等流程,掌握Spring解决复杂场景所运用的分治、抽象和知识(设计模式、设计原则),在解决Spring场景问题时,可以从核心原理上给出方案。同时也具备基于 Spring 开发 SpringBoot Starter 技能,为复杂项目减少同类共性需求的开发,凝练通用的技术组件,减少研发成本。

    1.2 深入学习 MyBaits 核心流程模块,包括;会话、反射、代理、事务、插件等流程,熟练掌握 ORM 框架的设计思想、实现方式和应用价值。并能按需结合 MyBatis 的插件机制,开发属于企业自己所需的功能,包括;数据分页、数据库表路由、监控日志、数据安全等方面。

  2. 体现在项目经验上,例如;—— 对校招和实习比较有用

    把 Spring、MyBatis 当一个学习项目来描述,这是你在离校前,最可能接触到的一个完整的、成型的、知名的,有企业使用的,框架。你就按照自己学习并开发了这样一个框架为目标来写项目,并描述出这个项目,你用了什么技术栈,解决了什么问题,学习到了哪些。

  3. 体现在项目应用上,例如;

    关于 Spring、MyBatis 的项目,一般都是插件类开发,比如各类的 SpringBoot Starter,MyBatis 插件,都是基于框架的深入整合类技术解决方案,体现在简历上,非常抓眼球。一看你就是有深度和自研能力的研发人员。—— 一般不让你造轮子,但需要你有造轮子的能力,这样企业中一些软件可以被你进行优化和修改。

  4. 体现在解决问题是上,例如;

    在你的自己的业务项目中,渗入一些关于解决了原项目使用 Spring 时,关于感知 Aware 方式或者结合 FactoryBean 包装对象等,所遇到的问题,因为你学习过源码,所以非常清晰这样的流程,因此解决了一个问题。通用 MyBatis 也适用于这样的描述方式,包括;事务、查询次数、批查询、插件能监听到的四个类(ParameterHandler、ResultSetHandler、StatementHandler、Executor )你给了更好的选择。

5. 更多场景