# 工作日記 #010 : 本週復盤 0505~0509 | 單一職責 SRP | 錯誤碼體驗 issue | Class 常數在 JVM 佔用的空間 久違更新一下工作的日記,說是日記但實際上是把這整週工作上遇到的一些議題做個整理,之後固定做個當週的復盤,紀錄每週的成長,而這週其實相較前兩週沒那麼有強度,但還是可從當中衍生出幾個我想紀錄下來的觀念和學習,分別是: - 初次在工作中聽到大名鼎鼎的「單一職責原則」。 - 我認為在工程上合理的流程,會有用戶體驗上的問題。 - Class 裡多新增的常數會存放在 JVM 的哪個空間。 ## 單一職責原則 「單一職責原則」這個詞應該可以說是軟體工程師的聖經之一,大家都知道它很重要,但不一定每個人都有確實實踐,也不一定每個情境下都必須實踐,還是需要根據需求去做一些彈性調整。 ### 需求 而我這週遇到的問題是,忘記密碼的 API 重置成功後會自動登入,但如果遇到有開啟 Captcha 功能的網站,會因為登入時需要輸入驗證碼而報錯,所以必須優化成「重置後兩分鐘內可以跳過 Captcha 驗證」。 這個需求牽涉到三個模塊: 1. 首先登入的主流程是在 Gateway 系統。 2. Captcha 驗證會 call 另一個 A 系統。 3. Geetest 驗證會 call 主要串接三方服務的 B 系統。 我一開始的作法是: 1. 重置密碼成功後會 async 發送請求給 A 系統,寫進一筆紀錄進 Redis 資料庫,TTL=2min。 2. Captcha 跟 Geetest 驗證時先判斷有無密碼重置的紀錄,有紀錄的話就不往下繼續驗證的邏輯。 ### 問題與解決方案 但這邊遇到的問題是,A 跟 B 兩個系統主要的職責是執行驗證的邏輯,判斷要不要執行則是 Gateway 這邊決定的,Gateway 擁有控制權,如果是到子系統才判斷登入要不要避開驗證,相當於把控制權從 Gateway 這邊交出去,這樣職責就錯亂了,所以應該是: 1. 重置密碼成功後會 async 發送請求給 A 系統,寫進一筆紀錄進 Redis 資料庫,TTL=2min(這邊保持不變)。 2. Gateway 登入時先去 call A 系統查詢是否有重置密碼的紀錄,結果返回給 Gateway 後,根據有無紀錄來判斷要不要再發請求給驗證 Captcha 跟 Geetest 的系統。 如此一來控制登入流程的這個職責就完全是 Gateway 這邊攬下了。所以在遇到多個微服務之間的改動時,要先去思考哪個微服務做哪些事、他們各自的職責為何?才不會後續不好維護或後面的人不好接手,工作起來的順暢度也會提升。 ## 錯誤碼體驗問題 跟上面同一張 Ticket 的問題,在登入流程中 Gateway 去 Call A 系統取得重置密碼紀錄時,假設 Redis 的節點故障,可能會拋出 Exception。 原本做法是讓它直接往上傳給用戶,因為我想說就算這邊不拋,到時自動登入也會拋出驗證碼錯誤的例外,那為何不先拋? 但我得到主管的說法是,拋出驗證碼錯誤比拋出系統錯誤的用戶體驗好一點,雖然我是不知道到底是怎麼個好法,但確實我只用工程的角度去思考合理的做法,而不是從用戶的角度去思考,這個觀點滿有趣的,下次要更多設想到 UX 的層面來做設計。 ## 常數在 JVM 裡佔用的空間 這也算是我在上面那張 Captcha 的單衍生出的問題,就是我在一個 Class 裡面定義了一個常數,而這個常數實際上會不會佔用到 JVM 的空間,而它又會被存放在 JVM 的哪個位置,什麼時候才會被拿出來使用? ```java private static final String DEFAULT_VAL = "0"; ``` ### Metaspace 這個 DEFAULT_VAL 的常數變數會在 JVM 運行時存放在本地內存裡,Metaspace 的 **Runtime Constant Pool**。 Metaspace 是在 JVM 裡用來存放 Class 相關資訊的空間區域,JVM 在執行中如遇到類加載的情況時,會把 Class 相關的 Metadata,如 Class 內的靜態變數、常數、方法等資訊存入 Metaspace。在 Java 8 以前這個區域被稱為**永久代 (PermGen)**,Java 8 以後被替換成 Metaspace,也從 JVM 堆內存移到本地內存。 JVM 在執行過程中遇到需要使用某個類時,會進行以下步驟: 1. 通過類加載器加載類的 .class 文件 2. 解析類文件的二進制數據 3. 將類的元數據信息存入 Metaspace 4. 為靜態變數分配空間(在 Metaspace 中) 5. 執行類的靜態初始化代碼(static 塊) Metaspace 的特點是,它使用的是**本地內存(Native Memory)**,而非 Java 堆內存 默認情況下,它可以動態擴展(直到系統內存上限)可以通過 **-XX:MetaspaceSize** 和 **-XX:MaxMetaspaceSize** 參數限制其大小,不受 Java 垃圾回收器直接管理,但類卸載時會釋放對應空間 ### Heap 引用 DEFAULT_VAL 這個變數的字串值 **"0"**,會存放在 JVM Heap Memory 裡的 **String Constant Pool**。JVM 裡的 Heap Memory 就是用來存放所有對象實例的空間區域,包括引用類型變數的實例、字串變數引用的值等等。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up