文章列表

如果把一款課金手遊當成單機speedrun遊戲玩會怎樣?

手機‧電玩
MacauYeah・2025-04-24

很久沒有介紹遊戲了,適逢最近有新的高達手遊推出,筆者親試下,遊戲整體還算不錯。所以打算就來個企畫,試試看用不同的方式去攻略這款遊戲。 以前的手遊玩不下去主要有幾點: 【農】味高,重要資源取得有限,有些需要週期性登入才能取得。登入取得資源,但過程又無聊;不登入又會浪費,多少有點壓力。 課金抽角色+練滿的金錢及時間成本極高,所以錯誤投資角色的成本就更高 所以最近筆者都鮮少有開始新手遊。這次的G世代,也是一款課金手遊,但為免陷入上述的困局當中,筆者就打算以研究Speedrun的角度去切入遊戲。即是不追求完美或者穩定通關的做法,只要本篇的能過關,越快過關越好。除此之外,Speedrun項目一般都會因為有公平性考量,在手遊上會禁止任何課金、什至是抽卡的做法,排除因為錢作怪,而非玩家的技巧。所以筆者也會跟隨這一方面的考量,除首抽可以選取特定的EX高達外,之後一律不會抽卡,即使有免費的抽卡卷或課金額,都不會抽卡。Speedrun也可以設定不同的比賽目標,例如限定從零到第一章結尾,並不一定要直到終章。目標一般會設定為可以重複為主。 這樣的做法可以讓自己免受前述情緒困境之中。 不需要為每日任務、完美過關的免費石而登入。想玩、有空玩時,再玩。 不需要為稀有角色的進一步團積它們的資源,因為它們的資源一般更難最得、更耗時間。 集中於本篇可以取得的機體,以不同的方式實驗不同的戰術效果,取代【農】的策略。 以推進本篇的主線為目標,而非收集角色為目標,也不是以平衝育成角色為目標。即使刪號重來也不心痛。 上圖為遊戲的第一、二、三章節 筆者經過零碎時間,剛通過了元祖本篇的章節,感受還不錯。筆者在開局,主要目標是選擇有【額外行動】、【支援攻擊】的機體為主,其次才考慮【支援反擊】、【支援防禦】的使用。當然這個遊戲推出時間還短,不同的機體取得時間上也有差異,筆者的策略絕對不是普偏的最優解。 上圖為開始攻略第二章所有在主線中取得的機體 如果各位讀者,覺得這個策略可以幫到你保持遊玩的好心情,就一齊來留言分享你的Speedrun策略吧。如果各位讀者想睇到更多關於這遊戲的策略更新,歡迎留言1212,讓筆者知道大家的期待。

Coding Anywhere: 依賴服務的選擇

科技新知
MacauYeah・2025-04-22

年多前,筆者購入steamdeck, 經過一輪軟件定制,把它變成一個可以作為IT從業員開發機的方案,也介紹了一些coding anywhere的想法 https://lifemag.cyberctm.com/zh_TW/blog/macauyeah/14175/Coding Anywhere 工作方案 https://lifemag.cyberctm.com/zh_TW/blog/macauyeah/14352/Steam OS 3.5更新,內建 podman, distrobox https://lifemag.cyberctm.com/zh_TW/blog/macauyeah/14149/開發者在Steamdeck上的另一個選擇: Gnome box 在試驗了一年多後,筆者對於依賴服務的模疑,又有另一層感受。什麼是依賴服務?就像你寫的程式庫,可能需要資料庫儲存、可能需要問AI等等。所以在開發時,都要確保這些服務的存在。一般,要麼就是在本機上自行安裝,要麼就是經過互聯網使用雲服務(public cloud或者你團隊提供的private cloud),也就是本地模擬還是互聯網模擬。 本地模擬的得失 本地模擬,主要是考慮金錢上的優勢與資源的獨立性。 金錢成本 - 互聯網資源大部份都不會是免費的,如果本機的硬件足夠,可以在本地完全模疑,有一定上的優勢。但如果該服務在本地安裝,都要計授權,可能不沒有太大差異,例如那些report engine, report designer,即使本地開發都要逐台開發機計算。但其他大部份,如資源庫的實現,都有本地開發免費授權。所以本地安裝道理上有一定的成本優勢。 資源獨立性 - 當一個團隊共用一些互聯網服務時,可能會互相干援。即使團隊在開發時,可以經profile使用不同的資源,但發生誤用的情況還是很常見。(除非大家已經有一套很健全的開發用profile,只在本機生效,亦只在必要時才會被提升到程式碼的版本控制當中,不會誤會地覆蓋他人,也不會忘了提交。但這是很有挑戰的一件事)。反觀本地模擬,因為那些服務並不會在團隊中分享,就保證不會被誤用。 學習成本高 - 本地模擬,就有一個莫大的痛點,就是學習成本高。我們可以找到很多本也安裝資料庫的教學,本地LLM AI的架設也不少。但我們並不是很輕易地就可以無師自通,有時為了初次安裝,所花的時間成本也大得令人卻步。 coding anywhere轉移成本高 - 因為全部本地模疑,代表我們必需要有一台足夠強大的主機。但如果我們的移動接入點,綁定了在某台特定的強大主機,我們活動空間也相對減少。 互聯網模擬的得失 直接使用互聯網的服務,主要體現於用錢解決問題的優勢 即開即用 - 能用現成的就用現成的。例如你目標是使用mysql cloud database,就直接伸請使用。如果你還要在本地安裝或使用Cloud VM安裝,就還要自行安裝管理介面等工具。因為成本問題,實在要自行安裝,使用cloud vm也有一定的方便性。使用cloud vm 有一定的快取,可以減少安裝所需要的時間。當我們養成自動化的習慣,clould VM 也可以隨時刪掉,有需要才重起。 解決單機無法模擬的情況 - 某性依賴,並不能簡單地經過本地單一部主機去做到。例如我們要模擬一些叢集功能。我們可能要在主機或網絡設備作出一定的調整,才可能提供bridge network。這一點在辦公室網絡下限制更多,不是隨便就可以建一個可以互通,又可以訪問互聯網的環境。另一些如block storage等資源,還會對硬件有一定的要求,也不是軟件模擬就可以做到。我們若不經過互聯網取得,至少也要在團隊下的private cloud上去建立。(不過如果是從零自建private cloud環境,初次投入的成本可能直接使用public cloud 低。 ) coding anywhere轉移成進一步下降 - 作為移動接入點,就剩下那些不可互聯網化的部份,例如domain name,有時還是localhost比較方便,又例如有一些硬件相關開發,硬件部份必需經過本地接入。 就以筆者的個人經驗來講,除非public cloud的價錢實在不可接受又或是自動化幾乎不可能,否則使用public cloud會有時間成本上的絕對優勢。如果要走本機模擬方向,必需要對Container、VM、網絡等有深刻的了解,才會成事。

Swarm mode 上線 6 - 2| 升級陷阱

科技新知
MacauYeah・2025-04-14

上一期筆者就介紹寺過swarm的相容性,可以任意地刪除其中node、加入新的node,系統會自動同步各機狀態。今日,我們就來討論一下加減的流程吧。 實戰輪調流程 假設我們有5個 node,都為manager,各個 docker 版本都為28.0.4 ,我們將要關掉node 5 (ubuntu 22),並加入node 6 (ubuntu24),輪調流程如下 如果node5有vvip,login node 5,關掉vvip systemctl stop keepalived login node1, 把node5降為drain模式,變為worker,並從群集中刪除 docker node update --availability drain node5 docker node demote node5 若然node5不是直接關機、刪除,只想好好地離開群集,可以 login node5, 在node5上預先執行 docker swarm leave docker node rm --force node5 如果之前node5有好好地離開群集,而且狀態已經轉為down,那麼就不用"force"了,用最保守的刪除指令就可以 docker node rm node5 login node1, 取得manager token docker swarm join-token manager node5關機,新增node6,使用相容的ip段,或者使用node5的ip login node6, 加入群集,設定vvip docker swarm join --token xxxx XX_IP:XX_PORT systemctl stop keepalived 這陷阱這陷阱 偏我遇上 上述的操作,有一些可能的陷阱,筆者就剛好踩過,未來不知道會不會有官方保證 docker的版本需要相同,不同版本可能不能加入群集,例如 docker 28.0.4 不能加到 docker 27.5.1。 docker 27.2.x 不能加到 docker 27.5.1。 docker swarm,官方雖然宣稱支援不同版本共存,但這指的是已加入的node,在不解綁的情況下原機升級。 在swarm已有多版本共存的情況下,有一個node選擇完全脫離,它想再加入,也是會失敗的。可能這不是docker自身的限制,而是底層library的相容性問題。筆者在實測不同版本時,就得到這樣的error。docker credentials: cannot check peer: missing selected ALPN property

Swarm mode 上線 6 | OS升級前的準備

科技新知
MacauYeah・2025-04-08

如果大家一直有跟進安全更新,基本上每個一至兩個月,都會有OS kernel和Docker Engine Update。也許大家習慣還是以不變應萬變,但有些時候還是不可避免地遇到嚴重漏動,需要強制更新。那麼當我們在這個情況時,我們該如何做呢?在開始做之前,我們先測試一下Swarm的容錯率有多高。 官方就宣稱,只要swarm中,manager例下的數目沒有超過半數,就依然可以運行。這個部份,筆者相信大家一早就感受過。但筆者認為,在直正出意外的情況是,少於半數的manager倒下了,但其餘的manager又不幸要重啟,到底又些活著的manager,又可否成功重新啟動?所以下面就來做些測試。 測試1 測試REPO 初始化script initDockerCluster.sh 筆者在原本的教學中,就有一個3個manager node + 2 worker node的範例,我們只要安裝ubuntu OS, packer, 並使用 # run setupMultipassWithFixIP.sh will install multipass and config fix ip ./setupMultipassWithFixIP.sh # install packer, please refer to https://github.com/macauyeah/ubuntuPackerImage/blob/main/README.md packer init template.pkr.hcl packer build template.pkr.hcl # initialize docker cluster in multipass ./initDockerCluster.sh 在上述的環境中,node21, node22, node23是manager, node24, node25則是worker。在全關的情況下,只要正常啟動兩台manager,worker就可以成功復活。 測試2 測試REPO 初始化script initDockerClusterLoopJoin.sh 筆者寫了另一個起始方案,會有5個manager node,而且依賴順序如下 node22 => node21 node23 => node22 node24 => node23 node25 => node24 node21 => node22 # initialize docker cluster in multipass ./initDockerClusterLoopJoin.sh 在上述的環境中,5台機也是manager。 initDockerClusterLoopJoin 的前半部份,它會建立順序依賴,即每一台機器,都經前一台機器進行加入的動作。而後半部份會把node21刪掉,並經multipass用一個全新的guest os重起,重新加入到。 在全關的情況下,只要正常啟動三台manager,它們都可以繼續運行。 這個測試的例子表明,即使原本作為依賴的機器死了,只要群齊中其餘多數manager仍然存在,它們也是可以復活的。更重要的是,即使最初引領一切的node21死掉了,什至是被刪掉重來,也是相安無事的。 結論 更新時,最保守的做法,是先加入新的manager,再除去舊有的manager。但這個做法下,manager的IP就不可避免地被改變。若然DNS或者防火牆沒有相應的自動化幫忙,先加入再替換就變得很痛苦了。 而上述的測試,其實代表了我們可以先暫停或移除舊有的manager,更新完後再接回去,這樣部份IP就可以重用。我們只要維持多於原本半數的manager活著,然後逐一替換或升級原有的機器,也不會有問題。即使在升級途中,其他manager不幸地斷線,重啟後它們還是有條件自行修復。我們也不需要顧及更新順序,只需想好Virtual IP的分配策略就足夠,其餘就像是單機升級一樣。

重入膠坑7 - 為自己的工作流程找最優解

手機‧電玩
MacauYeah・2025-03-28

前幾期,筆者有討論過如何避免山積的問題,主要是調整心理狀態。如果想要消山積,實際上我們還是要提高效率。 筆者在重入膠坑後,有時稍為認真制作,就會覺得有一些步驟很浪費時間。即使例如,打磨時,可否一口氣做完,減少換工具或換零件的時間。剪水口也是,我們有需要二刀流,粗剪取件,單刃修件,可否減少換來換去的時間?所有某些事件,需要事先規劃。 筆者是素組+補色向玩家,有一些筆者正在調整中的流程,大家可以參考一下有沒有更好的做法。筆者也是沒有固定工作檯的業餘玩家,有一些地方是考慮重複收拾的便利性。 剪件取件:全板剪下,每板零件放不同的盒保存。 刻線、油性滲線:用琺瑯漆滲線液的,可以在這階段作出。刻線失敗,也可以在後逐打磨中拯救。 打磨:逐盒零件打磨。同一盒中,每件零件用粗目沙紙打磨,同盒零件打磨完後換幼沙紙的,如此類推。打磨完到滿足的目數後,換下一盒打磨。 假組:把零都組合起來,但預期之後會再一次分拆,後逐會再加工。假組為的是想預覽一下整體外觀、造型,有那些地方需要補色、加工。確定要做的目標後,就用分件器拆件。制定目標部位必需要記下來,不然會漏。 刻線、水性滲線:用水性滲線液的,可以在這階段作出。跟琺瑯漆不一樣,是因為水性滲線液很易被打磨中的水帶走,所以還是打磨完再滲吧。 補色:追求官方配色,又或是刻出界,滲線攪錯了,現在就是用補色的好時機了。 組合 + 保護漆:兩者可能不分先後。有要求的話,可以組合前就上保護漆,也可以補色完成後馬上噴,以防刮漆。也可以組合後再噴,省點漆也省點時間。留意一定不要噴到連接樁上。 2B鉛筆走線:若然前述沒有用琺瑯漆、水性滲線液,噴完保護漆後,可以用鉛筆走線勾線。 拍照留念 以上是筆者認為理論上最少交換工具的流程,不會因為來回找工具而浪費時間,但可能亦會很枯燥。如果大家覺得枯燥,又可以試試以下分件流程。 準備取件表,再剪件:把說明書,一個區域的零件號碼抄起來(例如整個頭部或整個身體),然後一次過剪下該部份零件,一個盒就夠存放了。 打磨:與前述一樣。 補色、組合:回顧說明書及官圖,留意補色貼紙和額外的部份,補了再組合。但也因為某些零件需要組合起來才發現某些漏掉的地方,所以這兩個步驟會混合做。 刻線、油性/水性滲線:不拆件,直接刻線、滲線。因為前述有補過色,可能使用琺瑯漆便利性會大一點。不方便的地方,後最後再用2B走線。 保護漆:與前述一樣。 拍照留念 回到1,把所有的其他部份依次完成。為免枯燥,可能從頭、身、手、腰、腳、背包,依次制作。並將已完成的部份組合起來。 2B鉛筆走線:與前述一樣。 拍照留念 上述這個流程,就適合時間超級碎片化的用戶,例如筆者本人。不斷地切換工具,其實也會有額外開銷,不過好處就是很快就有可以把玩的部份,不用全隻完成。 我們再來一個簡化版,嘗試給快餐的朋友們。 準備取件表,再剪件:把說明書,一個區域的零件號碼抄起來(例如整個頭部或整個身體),然後一次過剪下該部份零件。最大差異是必需使用作最後一剪,因為不打磨了。 補色:大面積使用貼紙 組合:不假組了,直接組合。對照官圖,記錄需要額外補色的位置。 水性滲線:不拆件、不刻線,直接滲線,但只作用於粗坑線條上。水性滲線易於重做,溢出了重來也好。 補色:小面積部份使用Makrer筆 保護漆:與前述一樣。 拍照留念 回到1,把所有的其他部份依次完成。為免枯燥,可能從頭、身、手、腰、腳、背包,依次制作。並將已完成的部份組合起來。 2B鉛筆走線:高低差面,在噴完保護漆後,可以用鉛筆走線勾線。 拍照留念 這個簡化的流程,就適合盡快消山積的朋友。

練手的膠 - 1| HG EXIA能天使

手機‧電玩
MacauYeah・2025-03-24

之前筆者一直在分享膠模制作上的選擇,這期筆者就來分享一下自己踩過的坑,也許我們可以當作一個系列來分享。筆者參考一位內地up主,分享低價位的橂型,挑選適合練手的素材。不過筆者也只是一名新手,只可以從一些素組、打磨、補色方面,為大家導覽某些套件。筆者也不會限制於低價位的素材,只要有做過,也適合練手的,就會分享。有興趣新入坑的朋友,可以趁著再販期,一起入手筆者的舊套件,一起來體驗一步一步制作的過程。 第一期要介紹的,是2007年的推出的HG EXIA。Gundam.info的Youtube 頻道在2025年初,免費播放OO動畫,為這年的OO系列再販商品帶熱潮,筆者也想當然地趁著這個機會補票入貨。EXIA現在1/144比例中,可以通販買到的,就RG15、HGOO 01、HGOO 44,這三款。因為早期RG軟骨的問題,就沒有考慮RG,只有選擇HG。不過該HGOO 01是2007年的商品,真的不是一般的樸素。除了套件中原有的補色貼紙外,還需要進行多處補色。所以我們除了需要準備滲線、打磨工具外,還需要上色。不過筆者是簡化派,盡可能只用Marker筆補色,就結果來講,效果還不錯。 筆者就直接附上照片,指出這些補色的位置。 補色主要是天藍、深灰、淺灰、紅、黃、白 詳細圖片請見筆者IG 或者小紅書 https://www.instagram.com/p/DHfyseAvP8z/?igsh=MTc4Y3c5d29ydnJwOQ== http://xhslink.com/a/6d6BFOdGRzr8 留意手部前臂,後期滲線有機會流入透明件的地方。要先滲線再補色,最後才上透明件。 補充,條件許可的話,最後還是需要噴上保護漆,因為筆者用的是水性Marker筆,極易刮漆,多層保護漆,後期拿上手,壓力少一點。

重入膠坑6-補色地獄

手機‧電玩
MacauYeah・2025-03-23

之前筆者就有介紹過水性馬克筆補色、滲線,對於有一直砌開最新HG、MG的朋友來講,只需要考慮滲線就夠。但對於一些便宜價位的入門級的HG或SDEX模型,補色就更重要,因為它們的成型色大都只有兩至三種,即使套件中有提供補色貼紙,亦無法函蓋所有部位。筆者最近做的一款舊HG能天使及SDEX巴巴托期天狼座就是如些。 你所需要的是一套足夠便宜的平替 之前筆者亦介紹過【迪斯派】的模型專用的水性馬克筆,但對於這麼大量的補色,迪斯派的單價也是相當讓人心痛。最近筆者就發現到另一款更便宜的平替品,【多樂繪直液式丙烯馬克筆】。筆者寫稿當天,非金屬色中,也是45.8RMB 24色,72.8RMB 48色。相對於6.9一支的迪斯派非金屬色,多樂繪很便宜,顏色選擇也很多。 多樂繪亦提供散裝購買,7.9RMB 自選三支非金屬色,即是2.64一支。如果大家不想一次過全部購買24色,可以參考筆者以下型號 配合區部重塗: 600(白色), 603(黃色), 608(藍色), 622(淺灰), 680(深灰), 664(紅色)。上述與萬代的成型色還是會有色差,但相對不太明顯。其中600(白色), 603(黃色),遮蓋力較差,需要多次重塗以便發色。 還有一些筆者用到但不是通用色,628(天藍色?),642(海軍藍?) 使用效果: 筆者在塗裝部份只是處於基本補色要求,沒有試過混色、疊色、過渡等高階用法。對比迪斯派,多樂繪的感覺真的差不多。 操作 使用前先搖一搖筆身,拔蓋就用。 上色前需要打磨嗎? 對於白色、黃色等,先打磨模型表面,有助加強附著力。但白色始終難發色,也要多次重塗。深色的不用打磨表現也很好。 易刮漆嗎? 易刮,所以要留意邊角位。完成補色後記得上保護漆,上保護漆之前也記得再檢查一遍。 遇到的最大問題 多樂繪的黑色出墨過快,難以控制影響範圍,因為顏色太深,事後也很難清潔。但其他顏色未有出墨過快的問題,未知是否個別事件。另外筆者亦未試過傳統的水性消色筆,都一律以酒精或牙籤清理錯處,暫時無需使用專用消色筆(多樂繪可能也沒有消色筆)。 迪斯派比多樂繪做得更好的可能是出墨的部份,它不需要搖筆身,也有正常的顏色表現。但迪斯派的顏色選擇很少,灰色、藍色與萬代的成型色很不協調,小部份補色也很顯眼。筆者認為它最大的問題是缺少深灰色,這是萬代很多內構的常用色,再加上多樂繪價錢便宜一大截,一口氣買幾次回來粗用回本。 如果大家有發現一些更細微的分別,歡迎隨時留言交留。

Docker 中的非管理員用户 Docker non-root user

科技新知
MacauYeah・2025-03-14

Container USER為何重要 在制作Docker Image的過程中,有時會接觸到 USER 這個設定。這事關到最後的 Docker Container內部運行的那個 user 到底會有什麼權限。大家也要知道,Docker Container 其實也只是一個 Linux 上的程序,也就是如果Container內權限過大,也有機會從 Container 內部存取到 Host上的資料。 一般情況下,Docker Image 預設的 USER 就是 root,最基礎的base image都是一樣。而我們想換,其實也相當簡單,就像Linux上起User一樣,只要經指令RUN adduser xxx 或RUN useradd xxx 也可以在 Docker Image 中創建帳號和 home 資料夾,之後就隨時經USER xxx來切換 實際上是不是這麼簡單? 如果你將要Container中執行的程序,是一個binary,平常你在Linux中也是以 non-root 方式執行,那麼是的,就是那麼簡單。例如你執行系統中的java, node, python,原本在Linux中就已經是誰都可以,那麼你的docker container 也應該沒有難度。 但如果原本的安裝包,預設是由system service來啟動,我們就要花點力氣,看看那個service是怎樣呼叫binary的,然後就一步一步模擬它的做法。例如筆者有打包的codeserver,預設是system service啟動,但它也有提共binary的執行方法,安定好home資料夾後,我們也可以手動啟動。 泛生之檔案權限問題 上述binary的情境之所以簡單,是因為大部份情況下,我們都只對於container 內部運行考慮即可,因為預設投產情況下的運作模式,都是隨時起、隨時刪、隨時砍掉重練,只要container內部運作可以自給自足,就可以了。Docker Swarm的運作也是如此,所以它不預期有的持久化資料權限的問題。 而持久化資料權限的問題,其實早在單個Linux伺服器就已經存在。同一個伺服器中,不同process就有不同的UID,當他們需要共同讀/寫某些檔案,就會設定多人權限。同理,當多個Container要共同檔案,也是同樣問題。在討論共享檔案之前,我們先看看預設 Docker Storage Mount 會給我們什麼權限。 如果是bind mount,bind mount的權限預設會是Host內的檔案或者資料夾的權限。 如果Host是root,container內是non-root,container有機會無法讀寫bind mount內的檔案。 留意權限設置就可以解決問題 如果Host是non-root,但container 內是root,從container內生成的檔案,Host的non-root user就無法使用。 Host是non-root的話就一定無解,Host至少有sudo權限,臨時變成管理員,去修正問題。 如果host和container也是non-root,但UID不夾,其實也不能交換使用。 跟上述一樣,最後要靠sudo來解決問題。 如果host和container也是root,就沒有權限問題,但就有安全性的風險。 如果是volume mount,就還是看看 mount path 是docker image layer中現有的 path還是新起的path 大部份手動建立的named volume都是root 經docker compose起的named volume滿足以下條件的話,將會是non-root。 docker image 中的已有該path存在。 named volume未存在,docker compose會把對應path的內容在初次建立時抄到named volume 中。 例如ubuntu:24.04中的/home/ubuntu,存在於docker image中,它的擁有者就是UID 1000,我們經docker compose HOME_VOLUME:/home/ubuntu,在HOME_VOLUME建立時,就會是UID 1000。但如果是 NOT_EXISTS:/home/ubuntu/somethingNotExists,那麼NOT_EXISTS建立時,也會是root 上述討論的Storage mount是集中在單機情況下,使用HOST OS的本地儲存。若現在的場境是多機共享的share storage,就會更麻煩,還要看看那個share storage本身的屬性。例如常見的Linux NFS,其實有指定的權限,跟NFS的Login權限有關,如果你的process本身對檔案權限很敏感,就請先不要挑戰NFS(例如postgresql)。 Rootless mode - Rootless 模式 Rootless 模式指的是在Host中,執行Container的使用者,不需要是管理員,筆者就常用於開發環境中。投產環境中反而沒有聽過這樣的討論,因為投產環境很少可以讓非管理員去執行這麼重要的環境管理。 雖然只是開發環境,但這像前述的bind mount討論中,如果Host是non-root,但container 內是root,又或是兩者non-root,但UID不夾,也會出現權限問題。無腦的將host user加入docker group,只可以讓非管理員可以運行docker,但解決不了權限問題。 真正有條件解決的,可能就會向linux subgroup的方式發展。暫時筆者用得比較順的rootless mode,可以無腦用的,不是docker,是podman。有興趣的朋友可以經podman官網看看教學,它給筆者的感覺就像是自動轉換UID。 podman rootless mode 想看更多 筆者已經將過去的文章重新整理成gitbook,有興趣睇更多的讀者,可以來筆者的gitbook再翻一翻 https://macauyeah.github.io/AProgrammerPrepares/

Spring Boot 08 - 多情境設置 maven profile 與 application.properties 進階篇

科技新知
MacauYeah・2025-03-11

上期我們介紹完最直觀的用法,這期我們再來討論多管齊下的方向。 在開始之前,筆者總結一下上期的 Profile 的要點。 Spring boot 是經過 spring.profiles.active 去選擇什麼 (spring boot) Profile 生效 spring.profiles.active 它可以在runtime(運行時)動態更改 maven 是經過 xml 去選擇編譯時的 (maven) profile maven 編譯時為 spring.profiles.active 填入一個固定值 另外,筆者亦在測試途中,發現一個現像。 maven 並不提供混合 profile,即使下指令同時觸發兩個 profile ,最後亦只有一個 maven profile 生效。但這個部份筆者未在官方文件中找到,大家如果有任何發現,可以幫忙修正。 Spring boot 混合 Profile 當我們經IDE編譯時,可以為 spring.profiles.active 填入多個值,各值之間用逗號分隔,就可以觸發多個 profile 。 spring.profiles.active=dev,uat 程式碼中的application.properties, application-dev.properties, application-uat.properties 都會生效 Spring boot會先後載入上述三個檔案,如果有重複值,後面出現的會覆蓋前面的值。 spring.profiles.active如果填入的值與現在的application-xxx.properties不匹配,該部份不生效,例如 spring.profiles.active=dev,uat 程式碼中只有application.properties, application-dev.properties,但沒有application-uat.properties Spring boot會先後載入上述兩個檔案 上述的都好理解,當大家都接受上面的結論後,再來看這個現像。 spring.profiles.active 是啟動spring boot時,作為選擇profile的依據。 application.properties可以有一個預設的spring.profiles.active,正常跑spring boot就會看它。 正常跑spring boot時,還可以通過傳入參數--spring.profiles.active=xx,改變那個值。 Spring boot test 因為結構特殊,它只會看到 application.properties 中的那個spring.profiles.active值。 Spring boot test 暫時沒有方法傳入參數spring.profiles.active,但可以經程式碼 @ActiveProfiles 硬改運行中的 profile 。spring.profiles.active亦只會顯示 application.properties中的那個值。 Spring boot 混合 Profile 例子 大家看完概念之後,可以來看看實際例子。 當什麼都不加,就是根據application.properties的spring.profiles.active來啟動profile。 mvn clean compile spring-boot:run # or mvn clean compile package java -jar target/spring-boot-profile-0.0.1-SNAPSHOT.jar 正常spring-boot:run的情況下,可以經的 --spring.profiles.active 覆蓋過application.properties內的值。 mvn clean compile spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dev --spring.profiles.active=uat" mvn clean compile spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dev,uat" # or mvn clean compile package java -jar target/spring-boot-profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev --spring.profiles.active=uat java -jar target/spring-boot-profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev,uat 上述例子,若dev,uat內的值沒有衝突,沒有覆蓋問題。但如果有衝突,最後會是uat內定義的值。 Spring boot test Profile 例子 因為不是正常spring-boot:run,所以那些參數都沒有用,具體只會看application.properties內預設spring.profiles.active mvn clean compile test -Dspring-boot.run.arguments="--spring.profiles.active=dev,uat" # arguments will be ignored, same as mvn clean compile test Maven Profile 例子 加入Maven之後,就可以修改application.properties內的預設spring.profiles.active。但要注意,maven只會有單profile 假設pom.xml如下 application.properties如下 spring.profiles.active=@active.profile@ 下述三組例子,有且只有uat生效。因為maven的uat生效後,會修改 mvn clean compile spring-boot:run -Puat # or mvn clean compile package -Pdev -Dci=true java -jar target/spring-boot-profile-0.0.1-SNAPSHOT.jar # or mvn clean compile test -Puat 當然,你想要弄一個maven mix profile 也可以 以下例子可以令 dev, uat 同時出現在spring.profiles.active mvn clean compile spring-boot:run -Pmix # or mvn clean compile package -Pmix java -jar target/spring-boot-profile-0.0.1-SNAPSHOT.jar # or mvn clean compile test -Pmix Maven Profile Spring boot test例子 上述例子都了解後,最後就來看看全部混合的情況 當Test case中沒有硬改 profile 定義,application.properties中的spring.profiles.active就直接作用。以下情況就是同時運行dev,uat // java @SpringBootTest class ProfileTests { } // bash mvn clean compile test -Pmix 當Test case中有定義@ActiveProfiles ,application.properties中的spring.profiles.active的值會保留,但不在該test case中生效。以下情況就是同時運行uat,dev,但讀取spring.profiles.active的值會是dev,uat。 // java @SpringBootTest @ActiveProfiles(value = { "uat", "dev" }) class MultipleProfileUatDevTests { } // bash mvn clean compile test -Pmix 如果我們把maven 指令中的加入package,預期 test 執行的是 uat,dev 。而 jar 的打包結果會是 dev,uat。 // java @SpringBootTest @ActiveProfiles(value = { "uat", "dev" }) class MultipleProfileUatDevTests { } // bash mvn clean compile test package -Pmix 但請盡量不要這些做,因為會越來越混亂,特別是打包 prod 環境。為減少出錯的機會,例如test污染了prod的環境,筆者在package時,通常都會跳過test。 mvn clean compile package -Pprod -Dmaven.test.skip=true

Spring Boot 08 - 多情境設置 maven profile 與 application.properties

科技新知
MacauYeah・2025-02-25

為何要有不同的建構 Profile Profile這一字,很難在IT技術文章中翻譯,它在Spring boot中的語意大概就是一個設定一個固定的運行環境參數合。例如我們做開發時,有些只想在開發環境中出現的設定,諸如測試用的資料庫、細緻一點的LOG層級,都寫在dev profile中。當換成正式環境時,我們也有一套全新的配置,而且會集中寫在prod profile中。把這些參數設定從程式碼邏輯中抽離,可以讓你的程式碼簡潔很多,也方便對比不同環境的設定。 application.properties Spring Boot (Spring Boot Starter) 就提供了 Profile 管理。我們可以為一個Spring Boot 模組設定多個不同的 application.properties src/main/resources/application.properties 為預設 (default profile) src/main/resources/application-uat.properties 為驗收環境專用 src/main/resources/application-prod.properties 為投產環境專用 src/main/resources/application-test.properties 為自動測試專用 在執行程式時,我們只要動改變啟動的參數spring.profiles.active,例如 mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=uat" # or mvn package && java -jar target/YOUR_JAR_NAME --spring.profiles.active=uat Spring Boot 就會指定載入 application-uat.properties 的內容,如果有些值沒有定義,它會再追溯到預設的 application.properties中。 在運行中改變啟動參數的情況可能不多,筆者更常用的情況是在編譯期間產生多個 Jar 檔,不同 Jar 檔指定不同的環境,方便系統管理員取用測試。想做到這個效果,我們需要在 application.properties 中,我們還需要加入一句spring.profiles.active=@active.profile@,並在編譯工具中加入這個變量,例如筆者常用的 maven pom.xml 中,就會有這一串設定 它在 maven clean compile package 時,就已經可以在JAR中填入固定spring.profiles.active。那麼每次執行時,都會是指定的profile。 mvn package -Puat java -jar target/YOUR_JAR_NAME 在這個例子中,JAR 中的 spring.profiles.active 就會固定是uat,我們不需要在啟動參數中加入字眼。 如果大家不會碰到混合Profile的話,其實上述的資訊已經足夠大家應付很多情境。 但當大家有追求,需要寫自動測試,有機會不同自動測試需要啟用不同的 Profile ,更有可能出現混合Profile的情況,這件事就變得很複雜。我們需要繼續深入了解一下 Spring Boot 的覆蓋機制,下面將會以測試方式導出結論。 如果真的對混合 Profile 沒有太多信心,我們也可以用單一 Profile 重組不同 properties 的方式,自行去模擬混合 Profile ,例如除了dev, uat, test之外,我們可以加入 dev-test, uat-test, default-test 作為驅分。這樣應該可以簡化測試的複雜度,不過 properties 檔案就可能會成幾何級成長。 但在某情特殊情況下,我們不可能簡單地重組 properties 等型式去做測試,例如針對部份uat-test的測試,只有部份可以執行,部份不可以,那麼我們還是需要用到混合 Profile ,限定某些測試需要執個某個 profile ,但其餘部份可以動態切換。 有條件的讀者,也可以先行試玩一下混合 profile 的特性,下期筆者再為不同情況作解紹。 混合Profile Source code spring boot profile

重入膠坑5 | 堆積變山積,山積有辦法解決嗎?

手機‧電玩
MacauYeah・2025-02-20

針對大標題的問題,先講結論,堆積是沒法完全避免的,但我們應該有條件防止堆積變成山積(大量堆積)。 堆積不可避免的原因 以前筆者一直是玩遊戲多,面對特價節日買多了的現像,直到PS4後期,都還會有這個問題出現。但在過渡到PS5早期,就不再有這個問題。因為數位遊戲必定是越賣越便宜,除了機器壞、停產的問題,基本上不會有所謂的錯過好遊戲的問題。不同平台,每年都有節日特價,急玩頂多也就原價買入,能等就一定會有好價錢。 但模型可不一樣,實體商品都有限量的問題,首發一定貴,再販之後會回落到正常價,但再過一期就不一定有現貨。所以大家的策略一般是先買入自己認為不錯的新貨/特價品,以免後來買不到,即使山積也會照買。不過問題就是當年紀越來越大,又或是對制作越來越有要求,作業的速度就會越來越慢,然後山積就會越來越嚴重。 改變一下心態 首先這裏不討論成品玩具的山積問題,因為成品玩具至少可以折價出讓,只要夠捨得,想清貨一般都有市場。這裏講的山積問題主要是針對拼裝模型部份,針對那些要自己出手,慢慢一件件加工的玩具。 最初,我們可能很想完美地砌完一台模型,打磨、上色、擺拍。但因為一些技術問題,例如因為損毀要另行修復、制作難度、天氣問題、家庭問題,令大家的進度一直無法向前。久而久之,就會更無心情去完成作品,食之無味,棄之可惜。 面對這個問題,我們可以考慮放過自己,其實不一定要完美制作才能體現樂趣。素組,AA膠強行修復,遮醜,拍攝區部特寫,也可以一定程度的避重就輕地跳過有問題的部份。 貴精不貴多 由少量堆積變成山積主要的原因源自於【不想錯過】,但對於長遠目標來講,山積可能意義不大。 如果我們的目標是收藏,我們會想精制,而面對可能損毀的風險,雙入更具意義。所以不同時期山積多款模型,就變得沒有對沖意義。 如果我們的目標是重複把玩,我們可能更在意空間收納的方便性。若山積的話對於怎樣找模型,絕對是一個阻礙。舊模可能需要搬去一個更隱閉的地方,但這樣亦代表不再把玩,所以堆積也沒有價值。 重新定義如何斷捨離 回到本文最初的結論,堆積,或者叫作團貨,是沒法完全避免的。主要因為商品可取得性問題,再加上對珍品的不捨,一定量的堆積是必定會出現的。但我們可知道,物品始終都會老化或損壞,亦即是有保質期的問題,堆積不代表可以永久擁有。有些我們無法完成、修復的作品,就只好換個形式儲存,例如變成改件作為下一個作品的配件使用,又或是送出給下一位有緣人。新品購入時,亦要評估保質時間,自己是否可以在指定時間內開封體驗,免得錯過最佳觀賞時間。

Github copliot vs Intellij IDEA ultimate

科技新知
MacauYeah・2025-02-18

github copliot 最近正式開放每月限量免費使用,只要有github 帳號,就可以經過vscode copliot plugin,向 github copliot 交互式生成程式碼,又或是經 copliot 提供 code completion。大家會不會想過,加了github copliot的vscode,是不是效率暴升,可以跟傳統的付費IDE 例如intellij 的IDEA ultimate版本平起平坐? 流暢度明顯提高 是的,在生成程式碼方面,特別是code completion,在開啟copilot之後,實在好太多了。筆者長期寫java,vscode 原生的 java code completion,實在太陽春。java class name都很長,而且是強型別,很多時候都要完整打出class name。但大部份時候,筆者都要打很多個字之後,vscode才猜到你想打什麼,再給你可能的code completion,但這樣一來你也快打完了,幫助不大。要麼就是自己複制貼上,要麼就自己全拼出來。 在開了github copilot之後,在空行開始時,它就會開始猜你的意途,在打幾個字母以後,它雖然會頓一頓,但總在筆者跳去其他部份複制class name之前,就給出更新結果,實在省心太多。但猜測始終是猜測,大部份時候還是邊打邊修正。不過code completion方面,已經是追得上intellij,有些時候更是超越了intellij。例如我們有時寫 javascript 時,需要做多語言顯示,我們需要為每個語言設定一份i18n的翻譯。copilot 在這方面也能幫到忙,它會自動推薦可能的翻譯,你連問都不用問,這些功能,都不是 intellij 的本地運算會有的支援。 另一個要提提的是 copilot chat,它跟大家平時使用 chatgpt 程式碼生成的方面類似,只是它可以直接在vscode的某個檔裏直接交換生成程式碼。不過生成的品質都很一般,很初階的事可以做,深一點的就不懂。例如你很常寫java,但突然要寫javascript,有些javascript的array操作你懶得查,這時你可以叫copilot chat幫你生成。但若果你今日使用 javascript 框架,有一些 vuejs 或 reactjs 的結構參數傳遞你不太了解,你想找copilot chat,那就幫助不太。它依然可以生成一些程式碼,但對你碰釘的地方沒有修正意義。你還是需要自行從官方文件較對、研究Stack overflow中相似問題的解決方案。就跟chatgpt差不多。當然這些不是傳統IDE可以給你的。但如果現今對比的是收費的copilot chat和本地免費的ollama qwen2.5-coder,copilot chat就沒有太大性價比。 可以作為付費IDE的平替嗎? 如果我們拿vscode + github copilot 跟 intellij IDEA ultimate來比較,前者入門價錢是120美元一年,後者入門則是169美元(次年續期有優惠,但到了第三年才會比 github copilot便宜)。單看價錢的話,github copilot的確比較便宜。想省點錢,github copliot絕對是一個可以考慮的選擇。但除了錢以外,或者我們還要考慮一些其他因素。 公司立場上,介不介意你的IDE上傳資料到cloud service上面? 付費IDE的除錯功能、多環境整合、程式碼品質分析,這些關係到長期維護,非程式碼生成部份,是不是可以忽略不計。 筆者在開發開源的程式,長期都使用vscdoe,在配上 github copilot 後,明顯覺得它提升了 vscode 的流暢度。但相對實際工作上,筆者還是會集中使用 intellij IDEA ultimate 。因為即使vscode 有明顯改善,但日常碰到的問題更多不是在生成部份,而是解決那些似是而非的程式碼結構陷阱,這方面還是intellij 更幫到忙。(當然stack overflow和其他網路資源才是真正的救命靈藥。)

重入膠坑4 | 走線滲線的選擇

手機‧電玩
MacauYeah・2025-02-14

重入膠坑將近大半年,筆者陸逐實驗了過去不敢做的東西。前幾次就分享了剪鉗、打磨、補色的心得,時代真的一直在變,很多東西已經不需要大師級就可以動手做,而且有一定美觀效果。 例如薄刃剪+打磨+消光漆,已經一定程度可以淡化水口。用不著全上色,也就意味著普通人做個後樓梯勇士噴噴消光就可以了,其餘都是室內一般環境可以操作。當然打磨部份可能要加水,才能減少對健康的影響。 又例如補色方面,很多水性馬克筆可以選擇,軟筆頭可以大面積筆塗,很多品牌還是無味無臭,家裏隨時可以使用。相較以前動不動要用溶劑開油、洗筆,不方便且很大異味,水性馬克筆可謂極其方便。 這次筆者再來分享一下滲線和加深刻線的心得,希望退坑很久的淺度用戶們,有機會都可以試試這些簡單的操作,美化自己過去的作品。 2B鉛筆是神物 在十多年前,看教學,一定會教滲線筆和滲線液。滲線筆應該是那時候最易勾劃出立體感的工具。滲線筆其實是一些很幼細的油性馬克筆,但不論筆頭多幼細,走線時都嫌太粗了。所以筆者過去很長時間,都不滲線。但慢慢地,有網友提出了使用鉛筆勾線,一來隨手可得,二來勾錯也可以很容易擦了重來。 筆者試用過,大推這種做法。不過有兩點要注意的 筆頭要夠幼,走線勾線時才不會勾在坑的兩邊。平時寫字用的0.5是太粗了,那怕用畫面專用的0.3也是太粗了(也貴)。但其實我們可以自行手動磨尖筆頭,這樣才能上色到坑中間。不過磨尖了,代表筆頭很易斷,力度要很溫柔。 馬克筆上過色或上過消光漆的地方更易使用2B勾線。筆者未知確切原因,但感覺上是因為漆面不再原始膠面那麼光滑,質感更像A4紙張,2B筆跡更易留在模型表面。 加深刻線再滲線 在那個古早的過去,滲線液也是自行經法瑯漆稀釋調配。但現在就已經有現成的滲線液可以即開即用。某牌子的滲線液,其實也只是法瑯漆預先稀釋的成品,筆者也先針對這類滲線液做介紹。 這類滲線液是利用管線的毛細現象達到滲線效果,但為確保滲線液的流動性,模型原來的坑線需要先加深,而且在沒有消光漆的情況下使用。(如已使用消光,要重新噴光油,讓表面回復平滑,滲線後再重新消光)。這些都是教科書般的操作。 筆者想分享的,主要是刻線及滲線時機的部份。通常教科書是上色後再滲線,所以一般是假組、打磨、加深刻線、上色、滲線、保護漆(光油/消光)。但若我們只是素組補色,筆者就試行假組、補色、加深刻線、滲線、打磨、再補色、保護漆。 第一次的補色主要為大面積補色,補完後就進行刻線滲線動作,打磨要留在刻線之後,主要是因為刻線容錯率很低,不一小心就刻出界,打磨可以一定程度修補刻錯的地方。真的不行,就再少量補色。打磨過程也可能引起刮漆問題,再補色是必需要。 第一次大面積補色,若為淺色系列,可以用2B鉛筆直接走線勾線,不需要刻,減低出錯風險,劃出界也可以再補色。 水性馬克筆滲線 之前一直有講,水性油易被刮漆,但我們也可以反過來利用這點,直接用水性筆走線勾線。在沒有上色的部份,我們可以直接刻線,再用水性馬克筆走線。走完之後跟滲線液有少許差別,我們需要趁著水性油完全完乾之前,就用紙巾擦走多坑線周圍的部份。(但如果本身有上色,就只能回到2B鉛筆及滲線液的方向,這樣才不會出現擦走底色的問題。) 這個做法的好處是,我們顏色的選擇多了,也沒有法瑯漆X-20溶劑爆膠的風險。刻線部份依然會有出界問題,處理方式同前述一樣。 以下就是筆者運用上面所講的方式的實驗作品,右半是2B勾線及水性馬克筆滲線混合使用的效果,左半則是完全沒有塗裝/補色的狀態。

學習寫程式,除了複制貼上還有什麼?

科技新知
MacauYeah・2025-02-07

不知道大家是如何學習特定程式語言/框架的建構? 也不知道大家可如何保持程式庫/框架的最新狀態? 筆者就分享一下最新的經驗,看看對大家有沒有得著。 制作自己的範本 跟著程式/框架的導覽教學(Tutorial)走一偏 從零起一個新專案 設定專案,該用的基本功能全部設定好,作為概念驗證(Proof of Concept),也作為日後範本(Template)之用。 有需要用新專案,就複制之前的範本,再逐一修改名字或路徑的設定。 上述做法,是筆者過去比較常用的策略。面對很統一要求的專案,都有效。當程式庫有更新,我們可以選擇只局部修改,範本就可以長期用。我們也不需要經常從零走一篇。 練手的Code - 從零起一個新專案 上述的範本做法,對於現時需求多變的專案,可能不是很有效。例如有些專案使用Session Auth,有些則是Api Auth,有些則是Open Auth。同一個範本中有齊多種Auth的設定,原本難度就有夠高,之後複制完還要自行禁用不相關的部份,也是相當的煩人。當範本中多有個地方都有互相衝突的地方,複制範本就不是一個很易的做法。 面對那些複雜的配對,我們務必要真正了解技術的運作原理,然後為每個功能都從零建一個專案,做一個最簡單的Proof of Concept。重點不是在未來拿它們複制貼上,而是用來厘清概念,哪段程式對這個功能至關重要,哪段其實沒有作用。 如果可以,每次程式庫/框架升級時,都從零建一次。這樣一來可以練手,加深記憶,二來是每次版本的變動,有些程式碼可能已經變得沒有作用,原本的寫法並不再是最簡的。當然這個也可以為每個功能獨立做成範本,到有需要的時候再抄少量的程式碼就好。 其實練手的過程中,我們亦會慢慢熟習IDE的功能,有些IDE或Plugin已經很方便地自行完成一些設定。所以筆者漸漸的也習慣了不抄程式碼,改為以IDE Plugin的方式建立,某些真的很不熟練的部份才會維持範本複制的型式。 這是筆者最近學習vue3 的練習清單,還在持續新增中。讀者們有興趣也可以一起來修訂。 https://github.com/macauyeah/AProgrammerPrepares/blob/main/src/vuejs/TimeAttack.md