怎么做培训班网站,怎么做体育直播网站,网站如何做浮窗,购物商城网站建设今天#xff0c;我们将讨论在设计不足和过度设计之间保持简单#xff0c;愚蠢#xff08;KISS#xff09;和鲁棒性的设计价值之间的冲突。 我们正在编写一个批处理Java应用程序#xff0c;需要确保在服务器上一次最多运行一个实例。 一个团队成员有一个很好的想法#x… 今天我们将讨论在设计不足和过度设计之间保持简单愚蠢KISS和鲁棒性的设计价值之间的冲突。 我们正在编写一个批处理Java应用程序需要确保在服务器上一次最多运行一个实例。 一个团队成员有一个很好的想法那就是使用锁定文件这确实有效并且对我们有很大帮助。 但是最初的实现并不十分健壮由于对该死的应用程序拒绝运行并查找锁定文件进行了故障排除这使我们花费了宝贵的时间和昂贵的上下文切换。 正如Comoyo的ØyvindBakksjø最近解释的那样软件工程师与纯粹的编码器的区别在于它不仅思考和关注遍历代码的快乐路径而且也关注不愉快的情况。 优秀的工程师会考虑可能出现的问题并尝试适当地处理它们以便依赖于它们和其用户的代码可以更轻松地处理有问题的情况。 健壮性包括及早发现错误以适当的方式处理错误以及提供有用和有用的错误消息。 另一方面简单性[TBDHickey]是系统的关键特征。 花太多时间来制作防弹代码总是很容易而不是将精力集中在对业务更有价值的地方。 过于简单的实现 最初的实现非常简单 public class SimpleSingletonBatchJob {private static boolean getLock() {File file new File(LOCK_DIRECTORYFile.separatorCharConfiguration.getGroupPrefix());try {return file.createNewFile();} catch (IOException e) {return false;}}private static void releaseLock() {File file new File(LOCK_DIRECTORYFile.separatorCharConfiguration.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 doesnt 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}}
} 改进之处 如果不存在锁则创建一个存储锁的目录该锁不存在并导致混淆的错误消息“已运行”已经使我们痛苦不堪 有用的错误消息“锁定文件文件的绝对路径已存在。” 易于复制和粘贴int rm 。 有用的错误消息其中包含文件路径和错误信息当我们无法创建锁时空间不足目录权限不足等。 将整个主程序包装起来进行尝试–最后确保始终删除锁定文件 该代码仍然不是完美的-如果您终止了该应用程序则锁定文件仍将留下。 有多种方法可以解决该问题例如将应用程序的pid包含在文件中在启动时不仅检查其是否存在而且还检查该pid确实存在/是否为该应用程序但是在处理时间和增加成本方面都需要解决复杂性的确高于收益。 结论 KISS和鲁棒性都是重要目标并且经常会发生冲突。 使您的代码比必需的更健壮会使其变得过于复杂并浪费时间并且机会成本丢失。 由于故障排除使代码过于简单会花费您或它的用户大量时间。 要实现正确的平衡需要经验并不断地寻求平衡。 如果您的团队无法达成共识最好从一个简单的代码开始并根据其实际的健壮性需求收集硬数据而不是事先对其进行过度设计。 不要像我一样成为完美主义者但也要对您的用户和开发人员有益。 如果您可以毫不费力地使您的应用程序更强大那就去做吧。 如果需要更多工作请去收集数据以证明或不需要该工作。 参考 简单性与鲁棒性–在我们的JCG合作伙伴 Jakub Holy的《 Wonders of Code》博客上展示了锁文件处理 。 翻译自: https://www.javacodegeeks.com/2013/09/simplicity-vs-robustness-demonstrated-on-lock-file-handling.html