简单性与鲁棒性–在锁定文件处理中展示
今天,我們將討論在設計不足和過度設計之間保持簡單,愚蠢(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}} }改進之處:
該代碼仍然不是完美的-如果您終止了該應用程序,則鎖定文件仍將留下。 有多種方法可以解決該問題(例如,將應用程序的pid包含在文件中,在啟動時不僅檢查其是否存在,而且還檢查該pid確實存在/是否為該應用程序),但是在處理時間和增加成本方面都需要解決復雜性的確高于收益。
結論
KISS和魯棒性都是重要目標,并且經常會發生沖突。 使您的代碼比必需的更健壯會使其變得過于復雜,并浪費時間,并且機會成本(丟失)。 由于故障排除,使代碼過于簡單會花費您或它的用戶大量時間。 要實現正確的平衡,需要經驗并不斷地尋求平衡。 如果您的團隊無法達成共識,最好從一個簡單的代碼開始,并根據其實際的健壯性需求收集硬數據,而不是事先對其進行過度設計。 不要像我一樣成為完美主義者,但也要對您的用戶和開發人員有益。 如果您可以毫不費力地使您的應用程序更強大,那就去做吧。 如果需要更多工作,請去收集數據以證明(或不需要)該工作。
翻譯自: https://www.javacodegeeks.com/2013/09/simplicity-vs-robustness-demonstrated-on-lock-file-handling.html
總結
以上是生活随笔為你收集整理的简单性与鲁棒性–在锁定文件处理中展示的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 刺客信条奥德赛电脑(刺客信条奥德赛电脑配
- 下一篇: 如何查看自己或者别人电脑里的隐藏文件电脑