今天,我们将讨论在设计不足和过度设计之间保持简单,愚蠢(KISS)和鲁棒性的设计价值之间的冲突。

我们正在编写一个批处理Java应用程序,需要确保在服务器上一次最多运行一个实例。 一个团队成员有一个很好的想法,那就是使用锁定文件,这确实有效并且对我们有很大帮助。 但是,最初的实现并不十分健壮,由于对该死的应用程序拒绝运行并查找锁定文件进行了故障排除,这使我们花费了宝贵的时间和昂贵的上下文切换。

正如Comoyo的ØyvindBakksjø最近解释的那样,软件工程师与纯粹的编码器的区别在于,它不仅思考和关注遍历代码的快乐路径,而且也关注不愉快的情况。 优秀的工程师会考虑可能出现的问题,并尝试适当地处理它们,以便依赖于它们和其用户的代码可以更轻松地处理有问题的情况。 健壮性包括及早发现错误,以适当的方式处理错误以及提供有用和有用的错误消息。 另一方面,简单性[TBD:Hickey]是系统的关键特征。 花太多时间来制作防弹代码总是很容易,而不是将精力集中在对业务更有价值的地方。

过于简单的实现

最初的实现非常简单:

public class SimpleSingletonBatchJob {private static boolean getLock() {File file = new File(LOCK_DIRECTORY+File.separatorChar+Configuration.getGroupPrefix());try {return file.createNewFile();} catch (IOException e) {return false;}}private static void releaseLock() {File file = new File(LOCK_DIRECTORY+File.separatorChar+Configuration.getGroupPrefix());file.delete();}public static void exit(int nr) {releaseLock();System.exit(nr);}public static void main(String[] args) throws IOException {...if (! getLock()) { // #1 try to create lockSystem.out.println("Already running");return;}... // do the job (may throw exceptions)releaseLock(); // #2 release lock when done}
}

主要问题是,如果该应用程序失败或被杀死,它将留下锁定文件,而下次它将拒绝并以无用的错误消息开头。 您将需要了解/阅读代码以了解如何解决问题。

有人认为,这样的失败和故意的失败只会很少发生,以致于没有理由要求使代码更健壮。 但是,我们需要花费很少的精力来使代码更加友好和健壮,f.ex。 通过在错误消息中包括锁定文件路径并解释为什么可能存在锁定文件路径以及如何解决该问题(例如“如果应用未运行,则锁定是失败运行后的遗留物,可能会删除”)。 确保在失败时删除文件是一些琐碎的代码行,可以节省一些混乱和时间。 另外,值得一提的是使其更强大,从而不需要太多的手动干预–对您的操作人员很友好。 (我希望是你。)

更强大的实施

这是改进的版本,具有有用的错误消息,并在失败时删除锁:

public class RobustSingletonBatchJob {// Note: We could use File.deleteOnExit() but the docs says it is not 100% reliable and recommends to// use java.nio.channels.FileLock; however this code works well enough for usstatic synchronized boolean getLock() {File file = new File(LOCK_DIRECTORY, StaticConfiguration.getGroupPrefix());try {// Will try to create path to lockfile if it does not exist.file.getParentFile().mkdirs(); // #1 Create the lock dir if it doesn't existif (file.createNewFile()) {return true;} else {log.info("Lock file " + file.getAbsolutePath() + " already exists."); // #2 Helpful error msg w/ pathreturn false;}} catch (IOException e) {throw new RuntimeException("Failed to create lock file " + file.getAbsolutePath()+ " due to " + e + ". Fix the problem and retry.", e); // #3 Helpful error message with context (file path)}}private synchronized static void releaseLock() {File file = new File(LOCK_DIRECTORY, StaticConfiguration.getGroupPrefix());file.delete();}public static void main(String[] args) throws Exception {boolean releaseLockUponCompletion = true;try {...if (! getLock() {releaseLockUponCompletion = false;log.error("Lock file is present, exiting."); // Lock path already loggedthrow new RuntimeException("Lock file is present"); // throwing is nicer than System.exit/return}... // do the job (may throw exceptions)} finally {if (releaseLockUponCompletion) {releaseLock(); // #4 Always release the lock, even upon exceptions}}
}

改进之处:

  1. 如果不存在锁,则创建一个存储锁的目录(该锁不存在,并导致混淆的错误消息“已运行”)已经使我们痛苦不堪
  2. 有用的错误消息“锁定文件<文件的绝对路径>已存在。” =>易于复制和粘贴int rm
  3. 有用的错误消息,其中包含文件路径和错误信息,当我们无法创建锁时(空间不足,目录权限不足等)。
  4. 将整个主程序包装起来进行尝试–最后,确保始终删除锁定文件

该代码仍然不是完美的-如果您终止了该应用程序,则锁定文件仍将留下。 有多种方法可以解决该问题(例如,将应用程序的pid包含在文件中,在启动时不仅检查其是否存在,而且还检查该pid确实存在/是否为该应用程序),但是在处理时间和增加成本方面都需要解决复杂性的确高于收益。

结论

KISS和鲁棒性都是重要目标,并且经常会发生冲突。 使您的代码比必需的更健壮会使其变得过于复杂,并浪费时间,并且机会成本(丢失)。 由于故障排除,使代码过于简单会花费您或它的用户大量时间。 要实现正确的平衡,需要经验并不断地寻求平衡。 如果您的团队无法达成共识,最好从一个简单的代码开始,并根据其实际的健壮性需求收集硬数据,而不是事先对其进行过度设计。 不要像我一样成为完美主义者,但也要对您的用户和开发人员有益。 如果您可以毫不费力地使您的应用程序更强大,那就去做吧。 如果需要更多工作,请去收集数据以证明(或不需要)该工作。

参考: 简单性与鲁棒性–在我们的JCG合作伙伴 Jakub Holy的《 Wonders of Code》博客上展示了锁文件处理 。

翻译自: https://www.javacodegeeks.com/2013/09/simplicity-vs-robustness-demonstrated-on-lock-file-handling.html

简单性与鲁棒性–在锁定文件处理中展示相关推荐

  1. 怎么简单的锁定文件夹_简单性与鲁棒性–在锁定文件处理中展示

    怎么简单的锁定文件夹 今天,我们将讨论使事情保持简单,愚蠢(KISS)和鲁棒性的设计价值之间,设计不足和过度设计之间的冲突. 我们正在编写一个批处理Java应用程序,需要确保在服务器上一次最多运行一个 ...

  2. C#编码简单性之语义篇(如何编写简短的C#代码,随时更新)

    以前写C++的时候曾经在自己网站上发表过一个编码"简单性"之文章,现在编写C#了才发现自己无意之间就会写下一些浪费屏幕的代码. 下面是自己编码中偶然发现的一些案例,欢迎中等水平的编 ...

  3. C#编码简单性之代码篇(如何编写简短的C#代码,随时更新)

    以前写C++的时候曾经在自己网站上发表过一个编码"简单性"之文章,现在编写C#了才发现自己无意之间就会写下一些浪费屏幕的代码. 下面是自己编码中偶然发现的一些案例,欢迎中等水平的编 ...

  4. VMware Workstation提示:另一个程序已锁定文件的一部分,进程无法访问,删除.lck文件夹和文件

    一.现象 VMware Workstation提示:另一个程序已锁定文件的一部分,进程无法访问,截图如下: 二.原因 因为虚拟机在运行的时候,会锁定文件,防止被修改,而如果系统突然崩溃,虚拟机就来不急 ...

  5. TensorFlow 2.0.0-RC0版发布,专注于简单性与易用性

    TensorFlow 2.0 RC0 发布了,2.0 专注于简单性和易用性,主要特性包括: 通过 Keras 和热切执行轻松建模. 在任何平台生产中进行稳健的模型部署. 强大的研究实验. 通过减少重复 ...

  6. 锁定文件失败 打不开磁盘“D:\vms\S1\CentOS 64 位.vmdk”或它所依赖的某个快照磁盘(强制关机后引起的问题)...

    电脑强制关机后,centos系统启动失败,报异常:锁定文件失败 打不开磁盘"D:\vms\S1\CentOS 64 位.vmdk"或它所依赖的某个快照磁盘. 解决办法:进入D:\v ...

  7. android studio 使用SVN 锁定文件,防止别人修改(基于Android studio 1.4 )

    首先假设开发 A , 和 开发 B , 在使用 SVN 进行项目管理.那么A如何才能 某个锁定文件,防止B修改. 1.第一步,给这个文件加锁    完成这一步,则这个文件就别锁定了. 2.第二步,假如 ...

  8. 解决 锁定文件失败 打不开磁盘“D:\ubuntu\Ubuntu 64 位.vmdk”或它所依赖的某个快照磁盘。 模块 Disk”启动失败...

    一次在使用虚拟机的过程中,电脑出问题强制关机后,重新打开虚拟机,出现了"文件锁定失败",打不开虚拟机的情况. 上网百度查相关的解决方案,终于解决了问题. 因为虚拟机运行的时候会创建 ...

  9. php文件写入加1,PHP关于文件与目录(1) 写入文件 文件权限 三、锁定文件

    一.文件权限 总之一切都是为了保证目录的安全,保证目录的安全比保证文件的安全更重要. 二.写入文件 file_put_contents($file,$data); //如果没有的话会创建,有的话覆盖原 ...

最新文章

  1. 如何在空硬盘Linux系统,Linux系统如何新增一块硬盘
  2. 因果作用推断、因果网络学习及其他
  3. RDLC 2010设计器的数据源无法找到静态类作为数据源
  4. 建表时数据库建议使用 utf8mb4字符集
  5. 3 Python os 文件和目录
  6. HDU 5691 ——Sitting in Line——————【状压动规】
  7. 借贷宝java_【人人行(借贷宝)Java面试】借贷宝java后端开发面经。-看准网
  8. VirtualBox中安装Ubuntu、LAMP、SVN、JRE和Tomcat
  9. python的运行方式_Python的两种运行方式
  10. Spark2.1.0模型设计与基本架构(下)
  11. linux 定时关机命令,linux 定时关机命令
  12. java连接mysql lookup_Java数据库连接池lookup用法
  13. amd cpu排行_目前cpu排行榜(2020cpu性能排名对比)
  14. Microsoft Word 教程「3」,如何在 Word 中创建项目符号列表、显示字数统计?
  15. 第17节 三层交换机技术—工作原理及相关命令
  16. 录屏储存失败因为5823_为什么屏幕录制失败因为5823
  17. Bootstrap——网格布局
  18. 创建oracle的存储过程,以及通过JDBC调用该存储过程
  19. Rust之包,箱和模块管理(四):用use关键字引用其他包
  20. 2022年数维杯国际大学生数学建模挑战赛C题如何利用大脑结构特征和认知行为特征诊断阿尔茨海默病解题过程

热门文章

  1. python中的数组按顺序切片_python切片(获取一个子列表(数组))详解
  2. 小米miui系统已停止服务器,小米两款机型停止 MIUI 更新,明天发布最终体验版固件...
  3. thinking-in-java(10)内部类
  4. volatile关键字的作用
  5. 纯注解开发配置spring
  6. apache.camel_Apache Camel 3.1 –更多骆驼核心优化(第2部分)
  7. Spring Boot错误–创建在类路径资源DataSourceAutoConfiguration中定义的名称为“ dataSource”的bean时出错...
  8. java ee规范_测试Java EE 8规范
  9. lambdas 排序_Java8 Lambdas:解释性能缺陷的排序
  10. java泛型类指定多个泛型_Java泛型中的多态