10个好习惯

  1. 保持提交足够小
  2. 对于每一个想要的改变,先让改变变得简单(警告:这可能很难),然后再进行简单的改变。 PS:童子军原则
  3. 所有代码都是一种负担。未部署的代码是负担的死神。
  4. 知道何时在测试框架的能力。
  5. 如果某个特定功能没有合适的地方,就为它创建一个新的模块(或类或组件),你会在后面找到合适的位置。PS:不要过早设计
  6. 如果你不知道 API 应该是什么样子,可以先写测试,因为这会迫使你考虑“客户”,在这种情况下就是你自己。
  7. 复制粘贴可以一次。第二次你就引入了重复(即三份副本),不要这样做。你应该有足够的数据点来创建一个足够好的抽象。
  8. 设计会变得陈旧。你可以通过重构来减缓它们变陈旧的速度,但最终你需要改变事物的运作方式。PS:系统的熵增
  9. 技术债务可以分为三种主要类型:1)阻止您现在做事情的因素,2)将来会阻止您做事情的因素,以及 3)可能会阻止您将来做事情的因素。其他所有分类都是这三种的子集。尽量减少#1 中的内容,并尽量专注于#2。忽略#3。
  10. 可测试性与良好的设计相关。某些东西不易测试暗示设计需要更改。有时那个设计是你的测试设计。 PS:可测试性的重要性(如何写出可测试的代码??)

Things I Learnt The Hard Way

系统设计

  • 先制定规范,然后编写代码
  • 将步骤写为注释
  • Gherkin 是您理解期望的朋友
  • 单元测试很好,集成测试更好
  • 测试使 API 更优秀
  • 在命令行上运行您知道如何执行的测试(可以在持续集成工具中使用)
  • 准备好丢掉你的代码
  • 好的语言配备了集成测试 (如果一种语言在其标准库中提供了一个测试框架——即使是最小的——那么围绕它的生态系统将拥有比没有测试框架的语言更好的测试)
  • 未来思维就是未来垃圾
  • 文档是给未来自己的情书
  • 功能文档是其合同
  • 如果函数描述中包含”and”,那么它就是错误的
  • 不要将布尔值用作参数
  • 注意接口变化
  • 好的编程语言配有集成文档
  • 一种语言远不止是一种语言
  • 有时候,让应用程序崩溃总比无所作为要好
  • 如果你知道如何处理这个问题,就处理它
  • 类型说明您的数据是什么
  • 如果您的数据有模式,请使用结构来保持它
  • 理解并远离货物崇拜(”如果大公司在背后支持这一点,那就很好。”)
  • “合适的工具”只是推动议程
  • “正确的工具”比你想象的更明显
  • 不要干扰项目外的事务(改框架代码)
  • 数据流击打模式(当你理解数据在代码中如何流动时,你最终会得到比应用一堆设计模式更好的代码。)
  • 设计模式用于描述解决方案,而不是寻找解决方案(解决你的问题;找到一个好的解决方案;然后你可以检查模式以了解你如何命名该解决方案。)
  • 学习基础的函数式编程
  • 认知成本是可读性的杀手 PS:降低系统中总的认知成本
  • 神奇的七,加或减二(考虑函数组合, 而不是函数调用)
  • 快捷方式很好,但仅在短期内有效
  • 抵制“简单”的诱惑(对幕后的事情保持好奇。)
  • 始终在日期中使用时区
  • 始终使用 UTF-8
  • 开始愚蠢(脱离大型IDE工作)
  • 日志用于事件,而非用户界面
  • 调试器被高估了(日志记录可以在任何地方运行。你可能在崩溃时没有你想要的信息(例如,不同的日志级别),但你可以启用日志记录以便稍后找出一些东西。)
  • 始终使用版本控制系统
  • 每个更改一个提交
  • “git add -p” 是你在过度更改时的好帮手
  • 按数据/类型而非功能组织项目
  • 创建库
  • 学习监控
  • 配置文件是朋友(使用配置文件并用不同的配置文件运行应用程序)
  • 命令行选项很奇怪,但很有帮助
  • 不仅是函数组合,还有应用组合
  • 即使是应用程序组合,也要从简单开始
  • 优化是为了编译器(您需要做的是为您的代码思考一个更好的设计,而不是如何改进当前的代码。代码是供人类阅读的。始终如此。优化是编译器的工作。)
  • 惰性求值

团队协作

  • 代码审查不是为了风格
  • 代码格式化工具可以,但它们并不是灵丹妙药
  • 代码风格:遵循它
  • 显式优于隐式(sleep() -> sleepForSecs()
  • 公司寻找专家,但更长时间保留通才
  • 考虑用户
  • 处理用户数据的最佳安全方式是不捕获它
  • 记录“花费我超过 1 小时解决的愚蠢错误”
  • 如果它在你的电脑上无法运行,你就有问题

个人

  • 该停的时候就该停
  • 行为准则保护你,而不是他们
  • 学会说不
  • 您对您代码的使用负责
  • 不要在事情未完成时说“完成了”
  • 你将以艰难的方式了解自己
  • 人们对代码/架构感到生气/烦恼,因为他们在乎
  • 从你的烦恼中学习
  • 注意人们对你的反应
  • 学会识别有毒的人;远离他们
  • 注意微侵犯行为
  • 不,我认为它们是“不可修复的”
  • 有毒/微侵略者只有在你是他们时才能被修复
  • 英雄项目:你总有一天会做到的
  • 不要将“英雄项目”和“英雄综合症”混淆
  • 学会何时放弃
  • 信息技术世界是一个非常小的蛋
  • 纸质笔记实际上是有帮助的
  • Trello 很酷,但便利贴更好
  • 关于你愚蠢解决方案的博客仍然比保持沉默要好
  • 但关闭评论
  • 把你的愚蠢解决方案发布到网上
  • 保持“我不知道的事情”列表

REF

Spring Boot自定义参数处理实体ID

在实际业务中经常需要判断接收的实体ID是否在表中存在和向线程中注入该实体ID对应的数据,下面摘录了两种思路:

实现Converter来获取主键ID

1
2
3
4
5
6
7
8
9
10
@RestController
class GitRepositoryController {

@GetMapping("/repositories/{repoId}")
String getSomething(@PathVariable("repoId") GitRepositoryId repositoryId) {
// ... load and return repository
}

}

1
2
3
4
5
6
7
8
9
@Value
class GitRepositoryId {
private final long value;

public static GitRepositoryId valueOf(String value){
return new GitRepositoryId(Long.parseLong(value));
}
}

1
2
3
4
5
6
7
8
9
10
@Component
class GitRepositoryIdConverter implements Converter<String, GitRepositoryId> {

@Override
public GitRepositoryId convert(String source) {
// TODO 这里可以增加 exist 检测 和 在线程上下文中注入实体信息
return new GitRepositoryId(Long.parseLong(source));
}
}

实现 HandlerMethodArgumentResolver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@RequiredArgsConstructor
class GitRepositoryArgumentResolver implements HandlerMethodArgumentResolver {

private final GitRepositoryFinder repositoryFinder;

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameter().getType() == GitRepository.class;
}

@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {

String requestPath = ((ServletWebRequest) webRequest)
.getRequest()
.getPathInfo();

String slug = requestPath
.substring(0, requestPath.indexOf("/", 1))
.replaceAll("^/", "");

return gitRepositoryFinder.findBySlug(slug)
.orElseThrow(NotFoundException::new);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
@RequiredArgsConstructor
class GitRepositoryArgumentResolverConfiguration implements WebMvcConfigurer {

private final GitRepositoryFinder repositoryFinder;

@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new GitRepositoryArgumentResolver(repositoryFinder));
}

}

REF

0%