写点什么

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

作者:小傅哥
  • 2022-10-17
    北京
  • 本文字数:5477 字

    阅读完需:约 1 分钟

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

作者:小傅哥

博客:https://bugstack.cn


沉淀、分享、成长,让自己和他人都能有所收获!😄

一、前言:为啥不要你?

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


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


你肯定想,那为啥明明大部分时候都是 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 字样,这个是什么原因引起的。写代码要注意什么能避免产生这一种情况。

  • 测试:用数据库表防重做插入测试,触发异常;

  • 两个方法都加了事务注解,两个方法都会受到到事务管理的拦截器增强,并且事务传播的方式都是 REQUIRED,当已经存在事务的时候就加入事务,没有就创建事务。这里 A 和 B 都受事务控制,并且是处于同一个事务的。

  • A 调用 B,A 中抓了 B 的异常,当 B 发生异常的时候,B 的操作应该回滚,但是 A 吃了异常,A 方法中没有产生异常,所以 A 的操作又应该提交,二者是相互矛盾的。

  • 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

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. 更多场景




这些内容都来自于日积月累的思考和编写所产生的内容,也是更符合实际场景诉求的内容。—— 这让我想起有个为了卖 2 万多块钱的课胡说:”不会写贪吃蛇,进公司没法写代码!“千万别被这种忽悠了!


了解更多https://bugstack.cn/md/zsxq/introduce.html

发布于: 刚刚阅读数: 3
用户头像

小傅哥

关注

沉淀、分享、成长,让自己和他人都有所收获 2019-04-03 加入

作者小傅哥,一线互联网 java 工程师、架构师,开发过交易&营销、写过运营&活动、设计过中间件也倒腾过中继器、IO板卡。不只是写Java语言,也搞过C#、PHP,是一个技术活跃的折腾者。

评论

发布
暂无评论
面试官:深度不够,建议回去深挖_Java_小傅哥_InfoQ写作社区