- 作者:老汪软件技巧
- 发表时间:2024-09-25 10:01
- 浏览量:
你是否工作3~5年后,发现日常只做了CURD的简单代码。
你是否每次面试就会头疼,自己写的代码,除了日常CURD简历上毫无亮点可写
抱怨过苦恼过也后悔过,但是站在现在的时间点回想以前,发现有很多事情我们是可以做的更好的。
于是有了这篇文章。
小北将带大家从六个方面深入探讨如何在Java后台管理开发中不断进步,帮助你在职业道路上稳步前行
一、写优雅的代码优雅代码的重要性
优雅的代码不仅易于阅读和维护,还能减少错误,提高开发效率。对于后台管理系统,代码的整洁与规范尤为重要,因为它们通常涉及复杂的业务逻辑和大量的数据处理。
我们看一个简单的案例,我们直观的感受下,需求如下:
用户可以通过银行网页转账给另一个账号,支持跨币种转账。
同时因为监管和对账需求,需要记录本次转账活动
拿到这个需求之后,一个开发可能会经历一些技术选型,最终可能拆解需求如下:
1、从MySql数据库中找到转出和转入的账户,选择用MyBatis的mapper实现DAO
2、从Yahoo(或其他渠道)提供的汇率服务获取转账的汇率信息(底层是http开放接口)
3、计算需要转出的金额,确保账户有足够余额,并且没超出每日转账上限
4、实现转入和转出操作,扣除手续费,保存数据库
5、发送Kafka审计消息,以便审计和对账用
而一个常规的代码实现如下:
public class TransferServiceImpl implements TransferService {
private static final String TOPIC_AUDIT_LOG = "TOPIC_AUDIT_LOG";
private AccountMapper accountDAO;
private KafkaTemplate kafkaTemplate;
private YahooForexService yahooForex;
@Override
public Result transfer(Long sourceUserId, String targetAccountNumber, BigDecimal targetAmount, String targetCurrency) {
// 1. 从数据库读取数据,忽略所有校验逻辑如账号是否存在等
AccountDO sourceAccountDO = accountDAO.selectByUserId(sourceUserId);
AccountDO targetAccountDO = accountDAO.selectByAccountNumber(targetAccountNumber);
// 2. 业务参数校验
if (!targetAccountDO.getCurrency().equals(targetCurrency)) {
throw new InvalidCurrencyException();
}
// 3. 获取外部数据,并且包含一定的业务逻辑
// exchange rate = 1 source currency = X target currency
BigDecimal exchangeRate = BigDecimal.ONE;
if (sourceAccountDO.getCurrency().equals(targetCurrency)) {
exchangeRate = yahooForex.getExchangeRate(sourceAccountDO.getCurrency(), targetCurrency);
}
BigDecimal sourceAmount = targetAmount.divide(exchangeRate, RoundingMode.DOWN);
// 4. 业务参数校验
if (sourceAccountDO.getAvailable().compareTo(sourceAmount) < 0) {
throw new InsufficientFundsException();
}
if (sourceAccountDO.getDailyLimit().compareTo(sourceAmount) < 0) {
throw new DailyLimitExceededException();
}
// 5. 计算新值,并且更新字段
BigDecimal newSource = sourceAccountDO.getAvailable().subtract(sourceAmount);
BigDecimal newTarget = targetAccountDO.getAvailable().add(targetAmount);
sourceAccountDO.setAvailable(newSource);
targetAccountDO.setAvailable(newTarget);
// 6. 更新到数据库
accountDAO.update(sourceAccountDO);
accountDAO.update(targetAccountDO);
// 7. 发送审计消息
String message = sourceUserId + "," + targetAccountNumber + "," + targetAmount + "," + targetCurrency;
kafkaTemplate.send(TOPIC_AUDIT_LOG, message);
return Result.success(true);
}
}
我们可以看到,一段业务代码里经常包含了参数校验、数据读取存储、业务计算、调用外部服务、发送消息等多种逻辑。
在这个案例里虽然是写在了同一个方法里,在真实代码中经常会被拆分成多个子方法,但实际效果是一样的,而在我们日常的工作中,绝大部分代码都或多或少的接近于此类结构。
那么优雅的代码应该是什么样的?
public class TransferServiceImplNew implements TransferService {
// 可以看出来,经过重构后的代码有以下几个特征:
// 业务逻辑清晰,数据存储和业务逻辑完全分隔。
// Entity、Domain Primitive、Domain Service都是独立的对象,没有任何外部依赖,
// 但是却包含了所有核心业务逻辑,可以单独完整测试。
// 原有的TransferService不再包括任何计算逻辑,仅仅作为组件编排,
// 所有逻辑均delegate到其他组件。这种仅包含Orchestration(编排)的服务叫做Application Service(应用服务)。
// 我们可以根据新的结构重新画一张图:
private AccountRepository accountRepository;
private AuditMessageProducer auditMessageProducer;
private ExchangeRateService exchangeRateService;
private AccountTransferService accountTransferService;
@Override
public Result transfer(Long sourceUserId, String targetAccountNumber, BigDecimal targetAmount, String targetCurrency) {
// 参数校验
Money targetMoney = new Money(targetAmount, new Currency(targetCurrency));
// 读数据
Account sourceAccount = accountRepository.find(new UserId(sourceUserId));
Account targetAccount = accountRepository.find(new AccountNumber(targetAccountNumber));
// 获取汇率
ExchangeRate exchangeRate = exchangeRateService.getExchangeRate(
sourceAccount.getCurrency(), targetMoney.getCurrency()
);
// 业务逻辑
accountTransferService.transfer(sourceAccount, targetAccount, targetMoney, exchangeRate);
// 保存数据
accountRepository.save(sourceAccount);
accountRepository.save(targetAccount);
// 发送审计消息
AuditMessage message = new AuditMessage(sourceAccount, targetAccount, targetMoney);
auditMessageProducer.send(message);
return Result.success(true);
}
}
虽然功能都一样,但是在面试的时候写了上面的代码能得到了面试官的赞扬,而如果写成了上面的样子,估计不会有这种效果。
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]
二、提升代码质量
如果说优雅的代码是我们程序员的里子,那代码质量就是我们的面子。
想象一下,如果你写的代码,提测后测试出来各种bug,上线后也出现bug,就算你代码写的再优雅也没用了。
如何提升代码质量
想提升代码质量,最理想的是靠 code review,但是实际上这玩意在大多数公司根本就推行不下去。
为什么呢?因为大家都很忙,忙着改上一个迭代的bug,忙着写下一个迭代的需求,忙着做各种性能优化,忙着做各种日报、周报、月报等等...
所以靠人不如靠己,我们在日常工作中要善于利用工具,来帮我们发现问题,解决问题。
例如以下实践方法:
自动化测试:编写单元测试、集成测试,确保代码功能的正确性和稳定性。使用JUnit、Mockito等工具进行测试驱动开发(TDD)。持续集成(CI):通过Jenkins、GitHub Actions等工具,自动化构建和测试流程,及时发现并解决问题。静态代码分析:使用工具如SonarQube,对代码进行静态分析,检测代码中的潜在问题和代码风格违规。合理利用大模型,对我们的代码进行分析,发现bug。三、关注业务
看到这里有的人不禁要问,我一个后端开发,写好代码就行了,还需要关注业务吗?
如果你有这样的想法,那就大错特错了。
中国的企业,90%的开发都是面向业务开发,纯做研究的公司少之又少。所以你想要在互联网行业走的更高,那就一定不能脱离业务。
而且只有深刻理解业务了,才能对系统有一个整体的规划意识,才能设计出一个好的系统。
实践方法多与业务团队沟通:定期与产品经理、业务分析师沟通,了解业务流程和需求变化。参与需求讨论:积极参与需求评审和讨论,提出技术上的可行性建议和优化方案。业务文档学习:阅读业务相关的文档和资料,全面了解系统的功能和使用场景。业务架构梳理:梳理公司整体系统业务领域架构图,先从整体对公司业务有一个清晰的概念实践建议业务流程图:绘制业务流程图,帮助理解各个业务环节之间的关系和数据流动。用户故事:通过用户故事的方式,站在用户角度思考功能设计,提高系统的用户体验。持续学习:随着业务的发展,持续学习和更新业务知识,确保技术方案与业务需求保持一致。
四、培养架构思维
5年以上的程序员,就一定要培养自己的架构思维了,也就是要把自己的技术视角由自己的点扩展到线,再扩展到面。
从而对公司整体系统技术架构有一个整体的认知。
例如到一个公司之后,你一定要具有自我绘制如下技术架构图的能力。
架构思维的重要性
良好的架构设计是系统稳定、高效运行的基础。
培养架构思维,能够帮助你在项目初期做出合理的技术选型和系统设计,提升系统的可扩展性和维护性。
实践方法学习架构设计原则:如单一职责原则(SRP)、开闭原则(OCP)、依赖倒置原则(DIP)等,指导架构设计。分层架构:采用DDD领域分层架构,如适配层、应用层和领域层、防腐层,明确各层的职责,降低耦合度。模块化设计:将系统拆分为独立的领域模块或微服务,提升系统的可维护性和可扩展性。
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。这是大佬写的,[7701页的BAT大佬写的刷题笔记,让我offer拿到手软]