工程師的成長

https://limboy.me/2021/06/29/eng-growth 我覺得這篇寫算不錯,把一些必備的項目要點都有列出,對我來說反而是以下幾點比較關鍵: 累積 credit 信用值,才能提升影響力,講話才能大聲,別人才聽得進去 向各類型不同的夥伴學習他們的長處,儘管他們有著自己在意的缺點也沒關係,只要把重點擺在他們的長處並學習 如果對方是你欣賞的,要珍惜與他們共事的時間,遇到問題時,了解他們怎麼看待、處理、解決問題的

November 30, 2021 · Keanu Pang

BehaviorRelay 筆記

因為是單向的資訊流,在每次更新資訊時都是用 .accept 送出最近資訊,所以最好的做法是如果本身的資訊是組合性的 struct 則拆開成數個 BehaviorRelay 各別更新會比較好,這樣綁定在不同的 UIView 元件會比較好處理。 例如本來是長這樣: struct Info { var propertyA: Bool = false var propertyB: Bool = false var propertyC: Bool = false } 就拆成三個 property 各自維護: let propertyA = BehaviorRelay<Bool>(value: false) let propertyB = BehaviorRelay<Bool>(value: false) let propertyC = BehaviorRelay<Bool>(value: false) 然後就可以在 ViewController 層各別 Driver 綁定; 在最後如果需要組合判斷時才在用 Observable.combineLatest 來處理,例如: var isEnable: Driver<Bool> { return Observable.combineLatest(propertyA, propertyB, propertyC) .map { $0 && $1 && $2 } ....

October 26, 2021 · Keanu Pang

Failable Initializer 筆記

之前在 這篇文章 看到的。 將自己的 class 來做出一個可以是 optional 的物件,這樣一來使用的時候就必須用 if-let 或 guard 來讀取,在程式上會比較好理解跟處理。 直接上 code: class FilteredImage { ... init?(with imageName: String) { guard let image = UIImage(named: imageName) else { return nil } self.image = image } } 也就是說在初始化時是用 init? 的方式,確保回傳得到的物件要嘛是 nil 要嘛真的有值,而且對應的屬性也保證有值。 使用上也因為初始化回傳的是 optional 物件,限制了使用者必須用 if-let 或 guard 來拿取: guard let filteredImage = FilteredImage(with: "bird") else { // filteredImage is nil return } // filteredImage is initialized and we use it normally 然後要保持一個原則,回傳是 nil 一定是因為初始化失敗而得到的,如果是後面的行為造成的話等於權責不分無法抓住問題:...

June 1, 2021 · Keanu Pang

曾幾何時,人生的種種行為必須要虛偽的表現才算是正常了

自己所說的話所做的事,這些行為都要做的很表面做到位,對方才能夠體會到那所謂的”誠意”,很像電視節目的八點檔戲劇對話般,要正面有多正面,要積極就給到超過 100 分的積極。 對自己來說,大概也只剩下在停車場停完車後坐在駕駛座上遲遲不走的那時刻,才能感覺到真實自己的存在吧。

April 30, 2021 · Keanu Pang

建立 DynamoDB 的 Incremental ID 機制

需要在 DynamoDB 的某個 table 的 Hash Key 是用 auto increment 的方式儲存 id,不過如果只單靠一張 table 有點難完成這樣的機制,所以需要再生另一張 table 用來存放目前的值,讓原本的 table 可以去參考以取得新增後的數值回來儲存。 可以參考這篇:How to make a UUID in DynamoDB?,做法大概就是像這樣: Each time you want to generate a new id, you would do the following: Do a GetItem on NextIdTable to read the current value of Counter → curValue Do a PutItem on NextIdTable to set the value of Counter to curValue + 1. Make this a conditional > PutItem so that it will fail if the value of Counter has changed....

December 12, 2017 · Keanu Pang

在 Observable 裡做 recursive 操作

請參考 expand operator 的說明: Recursively projects each source value to an Observable which is merged in the output Observable. 在 expand operator 裡主要的判斷是如果離開這個 recursion 就回傳 Rx.Observable.empty();反之就把需要 recursive 的值修改後再回傳 Observable 物件,於是你的 Observable 物件就可以做類似 loop 的叫用串接了。 小範例如下,是用 AVA 做 test runner: const Rx = require('rxjs'); const winston = require('winston'); const test = require('ava'); const fetchObs = (count) => { return Rx.Observable.of({value: count, count: count*2}); }; test('test expand', (t) => { return fetchObs(1) ....

August 31, 2017 · Keanu Pang

Connect-Redis 套件更新 Session 過期時間的方式

在使用 Express 架設網站時,且因為 cluster 的考量,會將 Session cookie 的資訊往外拉,通常都是使用 Redis 來儲存使用者的 Session。在 Express 裡會透過 connect-redis 的套件來串接兩者,以及使用者登入的檢查就使用 passport 套件來幫我們完成。 在 Express 裡的設定結構大概會是這樣︰ let sessionMiddleware = session({ store: new RedisStore({ host: hostname, port: port, db: db * 1, ttl: 3600 }), resave: false, saveUninitialized: false }); app.middleware(‘session’, sessionMiddleware); 這時候的困難點會是當未登入的使用者可能需要 session cookie 的 maxAge 會比較短期,例如需要是處在 recaptcha 的驗證階段;直到使用者順利登入後,才需要更新 session cookie 的 maxAge 為合理的時間。也就是 Redis 的 TTL 設定是動態的方式調整。 參考這裡的 討論 的做法則會是固定將 TTL 設為 0,並在使用者登入後才更新 maxAge。所以 RedisStore 的設定將會是︰...

November 14, 2016 · Keanu Pang

自定 Retrofit 的 DELETE Annotation

一般使用 Jersey 或 RESTEasy 所建立的 JAX-RS Web Service,是允許 client 呼叫 DELETE method 時可以加上 Message Body,就跟 POST method 一樣我們可以取得 Body 裡的內容。 但 Client 如果是使用 Retrofit 來呼叫 Web Service 的 DELETE method 並且加上 Body annotation 夾帶資料過去時,卻會得到如下的訊息而被中止︰ Non-body HTTP method cannot contain @Body or @TypedOutput. 對 Retrofit 來說是照著 W3C 的標準去實作,於是這樣的行為就跟一般坊間的 http client 不太一樣。 最快的方法就是自定一個可以允許夾帶資料的 DELETE Annotation,讓 Retrofit 可以參照︰ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import retrofit.http.RestMethod; @Target(METHOD) @Retention(RUNTIME) @RestMethod(value = “DELETE”, hasBody = true) public @interface DELETE { String value(); } 然後在自己的 Retrofit Service 使用這個 DELETE annotation 就可以了︰...

May 4, 2016 · Keanu Pang

Create a Self-Signed Certificate

在工作上因為每過一陣子就會用到,但又常常忘記步驟所以筆記一下。 先用 opeenssl 指令產生私鑰跟 CSR 檔︰ openssl req -x509 -sha256 -days 3652 -newkey rsa:2048 -keyout server.key -out server.csr 建立憑證檔案︰ openssl x509 -sha256 -days 3652 -in server.csr -signkey server.key -out selfsigned.crt 將剛剛的憑證檔案轉成 P12 格式︰ openssl pkcs12 -export -name cert_server -in selfsigned.crt -inkey server.key -out keystore.p12 最後透過 Java 的 keytool 工具轉成適合 Java 環境使用的 JKS 格式憑證檔案︰ keytool -importkeystore -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias cert_server 完成收工。

April 30, 2016 · Keanu Pang