文章列表

Lambda 表達式之可讀性
科技新知
MacauYeah・2023-11-24

Java作為一個真OOP物件導向的程式,在設計和編寫上是很嚴謹,什至是囉嗦的程度。近年很多Programmer因為各種原因,都放棄Java跳船去其他語言。 Javascript是其中一個很多人的選擇,因為Javascript有nodejs的加持,在Web世界下,可以同時走frontend、backend路線。而Javacript亦有一個很明顯的特性,就是大部份的library都以callback的型式出現。另外,Javascript也讓很多人覺得很簡潔,這除了是因為它沒有強型態的規限外,另一個原因也是因為有callback的大量使用。 Function Pointer 其實callback,籠統一點講就是在一個function A傳入另一個function pointer B。而編寫function A的作者,並初期並不知道function pointer B的實際操作會是什麼。A作者只是強調在特別定時候,它就會使用這個function pointer B。而這種把function pointer 傳來傳去的做法,就可以看成是Functional Programming的基礎。 Functional Programming除了把function pointer 當成是一等公民以外,還有很多附加要求,例如: Pure Function 它只會使用到自己的Local Variable本地變數,這樣它的作用域就鎖死在Function內部,就不會有副作用。 傳統的OOP,Class中不少變數會以Class Attribute型式存在,雖然它們可能是private attribute,但還是獨立於Function外,這樣各Function的操作,都要靠作者好好地記著Class Attribute的狀態。 Nested Functions 與普通程式語言類似,很多情況下都需要local variable,而Function Programming要足夠好用的話,就需要彈性地在function裏定義local function pointer。 Java Lambda 表達式 其實從Java 8開始,就有提供Lambda表達式,這是一個可以制作匿名function pointer的方法。所以硬要講,Java也可以做Functional Programming。 但必需要盡早強調的是,Java經常性地使用class attribute,它們很多時候都會引申請狀態的概念。即是在它們必需經過特定步驟後,class attribute才會有特定的意義。也就是Lambda表達式想保持Pure Function的特性,它可以使用的時期就有很大限制。 但我們還有必要使用Lambda嗎 以筆者的經驗來講,它還是有作用的,特別在於它可以改善Class Function的閱讀性。 例如下面一個Java Class。它是一個工廠,提供一個服務可以生產一堆車。那些車而需要經過特定檢測,才能推出。 public class Factory ex1 public static List generateListOfCarByForLoop List tempCars = new ArrayList; many other logic many other logic many other logic List passTestCars = new ArrayList; for Car car tempCars if car.getWheels.size == 4 many other check logics many other check logics many other check logics passTestCars.addcar; return passTestCars; 中間的for loop可以用lambda來改寫。 ex2 public static List generateListOfCarByLamda List cars = new ArrayList; many other logic many other logic many other logic cars = cars.stream.filtercar gt; if car.getWheels.size == 4 many other check logics many other check logics many other check logics return true; return false; .toList; return cars; 有人會說,上述ex2只是形式上改變了,沒有特別易讀。就像ex3這樣,把特定邏輯抽成獨立function,才是真正的易讀,對嗎 ex3 public static List generateListOfCarByForLoopFunction List tempCars = new ArrayList; many other logic many other logic many other logic List passTestCars = filterCarsByWheelsSizetempCars, 4; return passTestCars; private static List filterCarsByWheelsSizeList originalList, int targetSize List passTestCars = new ArrayList; for Car car originalList if car.getWheels.size == targetSize many other check logics many other check logics many other check logics passTestCars.addcar; return passTestCars; 上述ex3是一個有效的改進。如果大家不計較傳入參數的先後順序及交互影響的話,就已經很足夠。 但如果大家對於多參數的解讀又怎樣 private static List someotherfunctionList cars, List wheels 大家又會不會突然停住,想想到底是cars影響wheels,還是wheels影響cars 對於多參數的function來講,相互影響就會越來越多,但使用Lambda的話,可以針對性地表達這是一個Predicate Lambda。 ex4 public static List generateListOfCarByLamdaComposition List cars = new ArrayList; many other logic many other logic many other logic List wheels = new ArrayList4; cars = cars.stream.filter filterCarByWheelSizePredicatewheels .toList; return cars; private static Predicate filterCarByWheelSizePredicateList wheels return car gt; if car.getWheels.size == wheels.size many other check logics many other check logics many other check logics return true; return false; ; 就最後的ex4版本,可以很明確的知道是cars被Predicate所作用。 如果大家還有其他使用Lambda的明顯好處,也可以一起來Github分享大家的Code

Switch / Steam Deck / Mobile 使用體驗大比拼 (一)
手機‧電玩
MacauYeah・2023-11-21

還記得很早開Blog之初,筆者一直都集中於主機遊戲評論。筆者不想放棄主機的主要原因是移動端難有一個款可以提供高品質的遊戲,不論PVE類型機還是PVP類型。 但逐漸地,各種遊玩動機,例如個人作息、方便性、遊戲品質,都有了很大的改變,經過漫長的時間,筆者最後亦都完全放棄主機,進入Portable Gaming時代。 筆者第一台便攜型機,就是PSV,不過因為已經停產,聊太多也沒有重要意義。但重提它的原因,主要一些操作體驗需要拿來做對比。那時的PSV,左右肩健各有一個,也就就沒有所謂的L2, R2 ZL, ZR,左右有類比搖桿L3, R3,所以當時完全是一個比PSP的進階替代品。筆者也對PSV有很高評價,因為它的重量、續航性、軟件穩定性,都對得起筆者的期待。亦因此,筆者對於第一期的Switch,都認真失望。不過Switch最後卻成為筆者現今最支持的平台,這亦主要是因為它的重量、續航性、軟硬件穩定性。 今期算是第一期,筆者就先從Switch、Steam Deck、Mobile的重量、型狀,來影響它們的便攜性。也因為一些外置設備影響,重量、續航性、軟硬件穩定性自己都會互相影響。 最輕的一定別無他選 Mobile 各大手機,在成型設計上,沒有預設手抦,所以一定是最輕的。但前題是你的遊戲對捽MON搓玻璃有做優化。現在很多競技手遊,已經發展出一套相對可以接受的捽MON設計,一些跨平台移植的PVE遊戲,亦都盡最大努力地加入附助機制援解捽MON下的不便。 但但但但,如果你需要真的最佳化操作體驗,Mobile配手柄的話,就不一定是最輕的選擇。在最入門的情況下,買一個很經濟的手柄,配上支架,你就可以把手柄、手機一起拿著玩。但問題是這會直接影響重量。最入門的選擇,手柄的重量通常都不輕。如果你配上一體式支架,手柄托著手機,就完完全全可以重過一台Swtich。有一些極致的手柄,可以很輕,合來會比Switch還輕。但這種很柄依然還有一個很大的天敵,就是不能與手機套共存。每次使用手柄,都要拆一次手機套。而手機套的設計,通常都是易裝難拆(這樣才能保證不便隨便跌出來),所以那怕你的手柄多輕,但每次你都要東攪西攪,便㩦性大打折扣。 結論是,若果你需要輕,而且即開即玩,你就要接受捽MON的選擇。你需要精準操作,就不能要求即開即玩。 巨無霸 Steam Deck 如果大家有一直接關於外文媒體,有時候你會看到它們評價Steam Deck的重量為:「沒有你想像的那麼重」。 That is fake!!!!!!! 老實說「沒有你想像的那麼重」,只能在你沒有比較對像時才能說得出口。在配上外設手柄的手機情況下,我已經覺得重,怎麼可能這台Steam Deck不重?抱著這台Steam Deck到處走,真的不容易。你想通勤期間想拿出來玩玩而整天背著他,不能說是很化算。你連續拿著玩個三十分鐘,也不是很好受。 不過筆者依然會覺得它有存在價值,主要是它可以帶著PS4以上的品質遊戲到處走,那些重量,是可以接受的。魂系遊戲、Capcom動作遊戲,也只有Steam Deck才能提供。想到處可以刷一場爽快的動作遊戲,有60fps,聲畫特效都打開,那是多麼美好的一回事。更重要的是,因為快餐打個兩、三場,也不過十五分鐘,電量不是筆者最大的問題。它預設的手柄按鍵也夠用。所以筆都會把它排在手機更高的評價。據說其他Windows掌機,更重、更耗電,很難想像它們還是走便攜路線) 結論:重,但可以滿足你的聲畫需求。 中規中矩 Switch Swich在預設配件的性況下,不重,除非你拿著玩超過一小時。Switch平常最多人投訴的是JoyCon手感問題。筆者覺得這是官方的一個合理選擇,對比PSV,什至更舊的設備,JoyCon不算手感差。最影響體驗的,其實是它易壞的問題。大家聽得最多的,是它搖桿的漂移問題。但其實還不止,手柄充電、接觸配對,都是可能出現問題。但老實講,手柄屬於消耗品,再加上JonCoy的內部的設計比同等體量的手柄要複雜,如果兩年換一套JoyCon,不能說是不合理的。 扣除JoyCon的成本差異性後,基本上它的重量很適合隨身攜帶,而且手感可以接受,它也有齊各個功能健、陀螺儀,在極致的體形下做出全功能的手柄,玩動作遊戲也是可以接受的。加下可拆性,就算壞了手柄,不用整台送修也是一個優點,找第三方手柄也是一個選擇。 結論,在於通勤的情況下,在原裝的情況下,就極快地從待機到進入遊戲,那是極重要的一件事。而且重量不重,每次帶著四圍走都不是問題,這也是它的面對碎片化時間之下,還能有高開機率的原因。 (最後筆者選了一套重量、價錢都合理的第三方手柄,它主要是不能當成無線手柄使用。但價錢便宜,而且手感更好,而且重量不會暴升。) 重量的綜合體驗 由可接受的重量範圍,Switch的便攜性最高,其次就是mobile,但在衡量重和按鍵的操作性,Steam deck 比mobile讓筆者更有遊玩的意欲。 下期,筆者會再從續航性方面去討論對於便攜性的影響。

澳門IT教育 | 到底現在缺什麼?
科技新知
MacauYeah・2023-11-10

筆者最近跟朋友聊天,也剛好在進修,談到一些IT知識的傳播問題。進修課的導師,或更廣泛的教育機構,都很積極地宣傳,人必需經常upgrade自己,接受新知識。而不同的導師,就是用不同的方式,去介紹新知識。而最普偏的知識傳播方式,就是人與人之間有溝通。 溝通,好像好實制好有效,對不對? 對。溝通是很易的,不過掌握知識,是很難的。所以阻礙大部份人持續進修的原因,其實是實踐知識的成本,包括時間、空間、金錢。但最近在接觸一些大公司的官方課程後,至少在software上,都有遠端的實驗環境。 Cisco 在多年前就有提供Packer Tracer,可以模擬一些網路情況。雖然不多,但至少可以實作打command。Oracle、SQL Server,現在除了提供免費的開發版本多,還有提供docker版本,希望把本地初次安裝的問題也解決了。Oracle的官方班,還會提供雲端的預安裝版本,你就可以省下本機資源做其他整合測試。寫程式方面,在早期,為推廣Web Frontend開發方面,已經有JSFiddle,很多朋友要試code,要做POC,都可以直接跑起程式看效果。這些,都是推廣IT知識的良好切入方式。 近年多得VM、Docker、VSCode,即使Web Backend,什至是Binary program,也完全可以提供遠端的實驗環境。良心的Github、GitPod,還有提供一定量免費的VM、Docker服務,你想把整個IDE放上Cloud,真的不再用像筆者以前要自己研究的CodeServer,用它提供的就好。不過遠端的環境還是有限制,例如你需要模擬硬件,或是需要很健全的測試環境,例如frontend backend cookie domain rewirte,又或是需要健全的除錯工具,都還是要等等。 好多事,雖然不能馬上上production,但look and feel,是吸引新朋友加入的重要關口。現今澳門IT的教育發展,就是總是留存在實體課,去指定的教室讀者PT教材,使用指定機器。若導師準備充足,就還好,可以順利實習,邊聽講解邊做實驗。頂多就是上課時間、地點不夠便利。但預者有一些老師不備課,食老本,Lab沒有提前預習,做live demo時才錯誤百,修正錯誤的時間成本很高。若要想更多人持續接受新事物,就必需要提供足夠多的可以實操的Lab,而且要可以自行重複。 對於澳門IT教育機構,希望可以提供更多的網上資源,讓學生可以解放地點和機器的限制。對於現在的ITSoftware的從業員,希望大家都可以擁抱DockerLinux Container,這樣才能最低成本地試用新事物。

Spring官方教學 | Spring Certified Professional 2023
科技新知
MacauYeah・2023-11-07

筆者作為一個網頁程式開發者,使用Spring Boot開發已經有六年。從當初Spring Boot 1.x開始,查看官方Tutorial七零八落,慢慢摸索,到大改版升級2.x,都碰過不少釘。最近Spring Boot亦要升級到3.x,正式進入Java 17時代。筆者亦不斷Update自己,保持程式於一個可支援的狀態。 相對以前,現在入門Spring Boot已經比1.x年代輕鬆很多。主要前些年某些網頁開發的概念,例如REST API,已經深入行業,大家不再糾結要走傳統MVC還是RESTFul API,也使得Spring Boot這樣的Framework,可以有一個受眾比較廣的統一入門教學。 筆者最近也正式參與Spring Academy的官方教學,好好地厘清一些概念。 官方連結 httpsspring.academypathsspringcertifiedprofessional2023 在讀過官方的幾個章節後,真的覺得很適合有興趣的人去看一看。主要是因為 官方以一個經典例子作為切為點,教學REST API,In Memroy Database。它還介紹了一些簡易的HTTP Code Standard、Test Case。真的比其他民間教學更有系統性。 提供一個可以在網頁上就實驗到的Lab實習環境。那是極為重要的一件事,因為九成人,在setup java 及library dependency maven, gradle時,都碰釘到直接放棄。有時是因為公司工作環境比較有要求,並不允許你使用一鍵安裝的java套件及它的library dependency;有時則因為網路安全,java把你公司的firewall當作a man in the middle MITM attack擋了,也有時是因為你公司的firewall把java擋了。Spring Academy在一個遠端的https網頁提供實驗環境,真的比本機開發要易入門很多。 Spring Academy可要多謝vscode、codeserver,及其他VM、Container技術。 在真實環境中,筆者也有自己的codeserver,打包java os cert等等,盡量減少firewall問題。 因為官方教學持續以Spring boot的最新版本作為教材,它更新的速度總比民間要快。只是官方的教學不會全面覆蓋到所有Spring project。如果大家作為Web入門的話,還是有推薦的。 在Spring boot 3.x當中,因為要求Java 版本至少為17以上,那些教材也有使用一些Java 17的新語法Syntax,實在也令人驚喜。 基本上Java 17現在可以簡化getter setter switch statement,這些在開發Web的環境下都是很重複的事。在Java 11或以前,只能經過IDE去生成getter setter等,但似始都有會一大堆Code佔據你的頁面。 官方教學及Lab環境暫時免費,除非大家很在意的修業證書,不然都可以自由免費看。 官方教學真的值得一看,雖然距離真正開發還差很遠,筆者日後若有條件,會針對官方沒有提及的內容作補充,分享一些在技術面上所需求的最少可運行配置。

Coding | Test Case 值得寫嗎?
科技新知
MacauYeah・2023-11-02

很多做軟件開發的朋友,其實都會聽過Testdriven的開發模式。就像Scrum一樣,名氣很高,但試過的人很少。為何會這樣呢?筆者認為,並非開發者懶,而是編寫Test Case的難度真的高。對比開發程式本身的成本,寫Test Case的時間學習成本一樣高。 造成這些高成本的原因很多。一來是因為開發者並不像過往一樣,慢慢從零寫程式,一般都應用Framework去預構建一些東西,例如打包Database connection pool,Dependency injection。Framework是好用的,但就令你要模擬Mock up特定資源,變得越來越複雜。所以一般中、小型開發,都鮮有人懂得做Test Case除了大神獨立開發者外。筆者對於Spring boot等Framework,都摸索了很久,才能模擬一些特定資源。但Framework一更新,就很多部份都要重寫。所以筆者沒有很強調要做Test Case,因為成本認真大。 最近,在摸清一些test case 基本concept後,筆者又重新開始嘗試編寫test case。以下假設用的是object oriented programming 在開發自己的class,為每個public function,都寫test case。很多IDE, 都有提供相關自動生成test case function signature的功能(就是為你的目標function,起一個只有外框的test function。)vscode雖然不是原生支援java,但只安裝基本的java test package,就可以達到同樣效果。 在不依靠framework的情況下,自己class要『引用』的其他class object,不要經過自己使用new來生成object。全部經set function來傳入你要引用的class object。除非你的class是作為Factory Pattern(工商模式)生產某些object,不然你就不會再有new字眼。 在為自己class編寫test case時,就會可以模擬被『引用』Object的行為。這個object在傳統上可以使用oop中的interface類型來達到模擬又不會影響到原結構的做法。實在不想做interface,java還可以用mackito 這個libraray來硬改Object的行為。 同理,自己class要『引用』一些外部資源,那些設定資源的config,都應該要set function傳入。這樣你在test case中才能起一個臨時的模擬外部資源。 在不使用framework的情況,要全數去自行模擬,當然很痛苦,但至少你可以做一些很簡單的測試。 在使用framework的情況下,還有些教學都是教你mockito繼續模疑。但這會是很痛苦的,因為這樣叫做unit test,單元測試,你要模擬所有東西。在折衷的情況下,應該底層元件做unit test,但上層的元件就做integration test,整合測試。 在做integration test時,就差不多等同使用framework行起部份或必要的資源。而那些必要資源,可能指是的database service, network service。我們可以在test case中設立不同的config,從而把framework指向一些備用資源。 Database好貴,腦細不會付錢set up多一套,自己電腦不夠強,也不能跑起多個開發用Database。好在還有h2 database可以幫你,它是memory可以操作的。只要你的framework支緩就好。在初次使用Framework時,你總會覺得為何Database層要設得這些抽像,其實為的就是讓你可以隨時換Database。不論做測試還是做移植,都會少很多問題。 模擬Network service還是沒有銀彈,要麼就mockito硬改行為,要麼就是提供一套測試用service。筆者曾經為模擬別人的Network Http API,也花了相當時間自己建立dummy server,提供模擬效果。無論dummy的效果有多假,有多局限,例如if id == 1,always return true,也是有一定價值。當你做source code refactoring (重構),又或是做framework升級時,還是讓你可以安心一點。

今時今日,課金手遊值得遊玩嗎?
手機‧電玩
MacauYeah・2023-10-20

原本筆者想做一個掌機遊戲 Switch,Steam Deck, Mobile Phone的詳細對比,但最近手機的手遊真的讓筆者有太多感受,所以筆者先直接聊一聊遊戲機制問題。 說實話,手機 Mobile Phone這個載體,一定是受眾最廣的。非競技類免費課金遊戲讓大家最開心,下載不用錢,開局刷首抽,不課也開心。而對於鍾情遊戲,用課金買資源,理應亦是符合輕、重不同情度的玩家。走一次性買斷路線的遊戲,也適合無網路情境。 免費課金遊戲又分兩大類,一些是買消耗道具,提供提示或額外資源,一些就是抽獎制,把某些特別資源限制在低機率的彩池當中。以最近的Monster Hunter Now為例,就是走前者路線。可以買回復藥或增加素材的道具,供特殊情境使用。以星穹鐵道為例,就是抽獎制,某些特別角色需要從彩池中抽出。 Monster Hunter Now鼓勵大家走出門,多去一些不同的地方,原意是好的。星穹鐵道設定階段等級上限,讓特殊角色跟普通角色差異有個限度,原意也是好的。上述兩個例子,都是鼓勵大家享受遊戲基礎玩法,不需要每一刻都想著課金問題。而筆者心中的強烈反轉點,亦是因為玩了這兩款遊戲,才爆發出來。 手遊發商始終要找到收益的來源,所以通過設計一些心理關口,等玩家忍不住的時候,就課金下去。營運需要金錢,合理回收成本,大家都應該可以理解。筆者對於之前一款競技手遊,也本著支持支持的態度,去課金兩三輪。因為遊戲課金目的很明確,就是提前解鎖指定角色。筆者課出去,亦玩到想玩的角色,大家都合乎預期。 但問題是MHN和星穹,雖然看似課也能玩,但實際上,兩者玩下去都很痛苦。MHN的資源囤積速度很慢,選錯武器走錯開發路線,想換武器就得花相當大的時間成本。即使課金,也不能取得指定武器素材,也不能指定出現的魔物,使課金的確定性變得很低很低。 星穹也類似,遊戲原本就有每日取得資源上限。課金可以抽多個角色,但無法讓你重塑角色。在資源有限的情況下,你不單要考慮養那個角色,還要考慮養哪個技能,壓力也真大。到後來,可能你更在意資源收益,去猛翻功略找養成策略,而不是去研究過關機制。 這還引伸另一個問題。我課金,為了更好地享受遊戲,隨時想玩就玩,忙的話,就先不玩,有時間,就多玩玩,但上述兩遊戲都不行。MHN課金道具染色球,亦需要玩家無時無刻打開遊戲,在指定的時空標記魔物。有空想多打兩場?不行。星穹的課金模式還有分一次性和月票制。月票制雖然每日資源變多,但你若很忙,沒時間玩,那天的資源就會浪費掉。之後即使你很閒,也不能多玩。 或者有人會說,無限課金不就解決問題了嗎?但這樣的話,筆者寧願支持買斷制遊戲,至少一次性付費之後,不論怎樣重塑,也是在連續的時間內可以重來的事,再加上對機制上的熟習,多次重塑的時間會會更短。 即使講了這麼多的不是,上述兩遊戲還是相當出色的。MHN以動作遊戲規格來看,是非常能發揮手機的便攜性同時能以最直觀的方式去實作動作遊戲的刺激感。星穹的聲畫演出絕對是上上成,回合制戰鬥並不讓玩家覺得沉悶。但兩遊戲的問題就是課金收益讓人蛋疼非常。 或許,之後筆者還是會出一篇掌機遊戲大評比,但可能課金手遊就不在對比範圍裏面,能比的就只有一次性付費遊戲

Miffy米菲控必去-澳門上葡京MIFFY創意展
生活在我城
MacauYeah・2023-10-17

唔知點解上葡京會唸到搵米菲做主題,哩隻來自荷蘭的公仔一直低調地遊走唔到國家但係澳門真係比較少出現,但相信米菲控一定知道佢係荷蘭同日本有幾受歡迎話說上葡京今次舉辦的MIFFY創意展由9月25日至11月12日係酒店舉行,場內唔同地方有超過100隻Miffy,還有 #Miffy主題下午茶、文創禮品、親子工作坊等,集打卡、美食、購物等等。 身為米菲控的筆者當然要帶埋佢個嫰B去探望吓咁可愛的米菲 周六1200首先去到酒店大堂酒廊嘆翻個 ldquo;Miffy 主題下午茶rdquo;費用MOP26815%,供應時間1100至1800再加點一個大蝦意粉先 落單後,係附近影吓靚相,之後好快等到飲品 圖1. Miffy Latte OMG好靚好靚好靚呀飲落還可以但沒有很驚豔。 圖2. Miffy Orange Ballon 香橙啡一望有點疑惑,但飲落特別可以哦很香橙味的咖啡。 圖3. 大蝦意粉 一大碟,小小辣,味道OK 圖4. Miffy吐司配雪糕 終於等到最期待的吐司,看着很美嘛,食落hellip;..外皮不脆,內里算軟,但除了上層有雪糕味,包有包味外,應該算是有點失望hellip;hellip; 圖5. Miffy朱古力焦糖撻 很美表面是甜甜的焦糖,下層是濃濃的朱古力,很甜甜的一道甜品 圖6. Miffy甘筍蛋糕 嗯以經有點飽,但咁可愛一定要試,係清香的甘筍味,蛋糕很軟。 食到一半,可愛的主角米菲登場,係場內大方同大家影相呀 嫰B更然立即衝埋去影相同摸摸啦 總結兩大一小食哩個餐一個意粉有點多,建議單點自己想食的都很足夠不一定要點餐,但米菲控叫一個主題餐是常識吧哈 食完仲可周圍行吓,場內仲有好多不同大小設計的米菲公仔同精品,歡迎大家一齊黎同米菲見個面哦 資料補充 上葡京官網 httpswww.grandlisboapalace.comtcrestaurantsnbarsglplobbylounge 餐廳不可預訂, 餐廳登入澳娛會員有95折(可以提前登記) httpssupremecard.sjmresorts.comtcmymembership

SCRUM:用一半的時間做兩倍的事
科技新知
MacauYeah・2023-10-13

這個假期,筆者沒有再去寫Code增值。取而代之的是看看書,吸收一下新思維,把頭腦好好更新一下。機緣巧合之下,翻開了早在幾年前就讀過的書《SCRUM:用一半的時間做兩倍的事》。當下心頭一陣心酸,為何SCRUM明明是資訊行業裏面的表表者,但自己在實踐上,就總是無法應用?所以又重新讀了一遍。 先講講SCRUM是什麼,SCRUM是暫件開發上的一種迭代模式,它有另一個名字,也是我們更常聽到的是【Agile敏捷開發】。它主張的是以最短的時間,造出最少的實際產品,讓客戶真的可以驗證當初的需求是否合理。而不是像瀑布式開發,先做好最前面,再做中間,再做最後面,然後再等客戶總體驗收。非科技業的朋友,可以想像成是ISO 9001機制上Plan Do Check Act。 理論筆者就不講太多了,筆者直接就講講實務上的問題。 首先,你要有一個團隊。沒有團隊你就不能在相互幫忙的情況下得益 但不是坐在同一辦公室的就叫做團隊,大家要真的一起協調,大家的目標和時間上可以協調,會一起幫忙解決他人問題的才叫團隊。所以,大部份情況下,當公司為了方便管理,都希望一個人負責做一個Project,每個同事是自己的project的Team Leader,這就沒有了緊密合作的意義。 你要有做專心做同一Project權限。這樣你才不會因為分心,因為做轉換,而浪費時間。 但基於公司營運,接新單新Project一定會天天都接,即使同事手頭上舊單未完成,都要強行跟同事加入新的工作說明,著手新Project的酬備。主要是因為平均分配各個客戶的期待,每個Project都要定期交點東西出來。公司也認為每個Project不可能一口氣進行下去,總有些時候是要等客戶、供應商回覆,轉換Project才不會讓同事閒著。 你要有心力去解決實際問題,讓你工作越來越順暢。這樣才會越做越快。 但問題總是每日新鮮,特別是你每次都要接觸新事物,解決方案亦不是一天就可以想到,所以會讓人失去衝刺的熱情。 運用了SCRUMAgile開發後,應該可以走少很多不必要的路。 但其實只有你在基礎能力都很超班,新事物都不用掃雷,你才會有可能覺得少走點。就以軟件開發來說明,若你沒有自動化的CICD的伺服器,每次都要花很多時間才完成發佈,你想讓客戶驗收新功能的頻率一定很低。你的同事連SVNGit都不用,你想取用他人的新功能來測試的難度也很高。你的開發環境沒有分為開發測試驗收上線,開發時改爛了就根本無辦法Rollback。及早驗收這不是代表你做錯事的機會變少,只是提早一點知道,讓錯誤不會繼續延伸下去。因為要重新改造而花掉的成本也是很明顯的。 一切一切在重讀《SCRUM:用一半的時間做兩倍的事》時,筆者也看到一些人生的希望。 若沒有團隊,但只要堅持專心做同一個Project,單人團隊也是一個可以嘗試的方向。當你專心做同一件Project,你會少了轉換成本,也不會感到同時多個Project的爛尾感,更容易累積信心和成就感。 當有問題真的解決不了,不是轉換Project,而是面對問題,要麼Workaround,要麼就解決它,把新增成本交給客戶老闆做決定。因為Plan Do Check Act的週期性,即使不是開發出完全滿意的產品,至少客戶都有部份功能可以用,也驗收過。公司收帳也應該跟開發期週期掛鈎,驗收過了,就收回開發費用。雙方有意見,不願意繼續開發,就按照剩餘未開發的部份收取解約金。以醫院的收費模式來舉例,一個慢性病,不會一下就可以治好。每次覆診,都會獨立計算診金,病人不願意繼續,可以選擇轉醫院;自己認為足夠了,也可以不再去覆診。 如果客戶老闆沒有因為堅持最初的合約一字不改,後續因為分歧而產生的負面情感也沒有這麼大。有些問題,可以及早止蝕,對公司與客戶都好。作為員工,在中間做磨心的情況也可以減少,不必為一開錯誤的開頭而繼續走下去。

Steam Deck With Podman
科技新知
MacauYeah・2023-10-06

Steam Deck With Podman 眾所週知,Steam Deck預裝的是一台Linux主機。但它的系統比較特別,為了可以安全更新,所以系統最主要的部份都設定為唯讀read only。也就是,傳統你可以直接在Linux上經管理員權限安裝的軟件包,全部都會被擋,即使你把唯讀部份設為可讀寫read write,在下次更新時,都會被一次過覆蓋掉。 筆者作為一個負責任的機迷開發者,怎樣可以白白讓一台Linux機只可以玩遊戲呢 怎樣跟老婆交代呢 所以筆者千辛萬苦,找到一個折衷方案,讓他可以當為開發機使用,那就是Podman。當然,若果大家有條件有金錢,直接改裝Windows就可以了。 Podman是什麼 Podman跟Docker一樣,都是一些管理和運行Container的主程式。跟Docker不一樣的是,它是Open source,而且是daemonless。 所謂的daemonless,就是不會有一個背景程式去長期管理Container。好處是不會因為背景程式死了,就全部Container一起掛掉,預設也不需要走管理員權限路線。但也因此跟Docker有一些使用上的差異,例如Podman沒有原生的dockercompose結構,即使坊間有python寫的podmancompose去硬對應dockercompose,但某些network是跟結構還是不能直接從Docker轉移過來。 就筆者早期的踩雷經驗而言,用Podman跑起一兩個獨立固定Port的Container來說,都很夠用,也不會遇到奇怪的Bug。所以這次,亦用來作為Steam Deck運行整合式開發的Container。 不平凡的安裝之路 install homebrew Steam OS 3,雖然可以使用更改read write,再使用pacman來安裝podman。但因為Steam OS更新後,全部要重來,工作量和網路流量都不少,所以筆者改為使用homebrew來安裝podman。homebrew只需要首次安裝時使用管理員權限,之後就會在home資料夾下留下可執行的程式,所以它不會被Steam OS更新所破壞。 install podman 記得記得重新開機,之後應該就可以成功運行container

Design Pattern: Observer / Subscribers - Push vs Pull
手機‧電玩
MacauYeah・2023-09-29

相信一般入行IT不久的朋友,都會知道IT系統更新時,有推和拉push、pull兩種方式。特別是Programer,對於觀察者模式又或者是訂閱者模式Observer Subscriber 會有更多的使用經驗,例如OS programing要處理event bus,Mobile App要做的推送通知Push Notification。 但一般來說,很少人討論推和拉push、pull的問題,筆者就著一些踩過的坑來說說差異。 首先,在一個通訊相對穩定的系統中,Push、Pull都很好用。例如同一個OS內,它的socket或pipe可以看作很穩定,可以假設那些要廣播的消息可以正常傳遞出好。但好用歸好用,這個模式對於越來越複雜的交互系統都有一個無法明確處理的問題:怎樣去處理觀察者訂閱者自己的操作失敗問題。 對於非IT行業的讀者來說,只要你接觸過手機即時聊天程式IM,如whatsapp, wechat, facebook messenger應該都會遇到一個問題就是:你收到OS提示通知,但打開聊天程式卻看不到新的對話內容;又者是你連續收到多個同一個內容的提示通知,那怕你已經讀過了。這些都代表了,手機端當初時沒有好好即時回應是否已經操作成功,不需要重複通知的問題。有可能是手機當時掛了,也有可能是網絡不太好。 上述的例子,對一般人來說,可能影響不太。因為重複收到訊息,又或是漏了訊息,也不會怎樣。但對於業務系統,例如定期收費,多收一次又或是少收一次,都會引起某部份關係者的不滿,即使事後有退費機制,但有些匯率問題,始終會有差異。在傳統架構上,有規模的公司系統都可能會使用內部的中央資料庫等做交易transaction管理,整個過程,都要嚴謹地記錄廣擴是否成功、觀察者自己的操作是否成功。 在近代,分散式系統又或是微服務的出現,令上述的中央資料庫無法實行。如何好好地重新定義好Transaction管理,就是一大挑戰。筆者最近亦實作了一個要在微服務的上廣播的觀察者模式,但雪上加霜的是,在互聯網的環境下,廣播的消息沒法保證可以正常傳遞出好。觀察者訂閱者可能已經正常收到消息,也做了相應的操作,只是來不及回應,網路就斷了。這令重複發送信號的可能增加了。 如果說,要以平民的方式去實作這類廣播,Pull會比較有大的容錯。廣播者只是通知觀察者訂閱者來拉資料,保證廣播當時的資料量可以盡量地少。廣播者開放盡量大的查閱權,觀察者訂閱者可以自由決定事後更新要取得的資料量。但這樣每個觀察者訂閱者都要重做一次同步機制,不過好處是,主動權在於他們自己手上。 相對地,Push的容錯就低一點,但要付出的成本也跟Pull差不多。因為網路環境,大家要重現一個基於TCPIP而有commitrollback的難度較大。當網路出現斷線,廣播者無法確定是否需要重做。在重複收到訊號時,最後還是需要觀察者訂閱者來決定怎樣處理重複記錄。但比Pull好的是,Push可以限制單次訊號的傳送量,也可以確保觀察者訂閱者一定收到特定的記錄。 上述就是筆者在這一年來遇過的坑,如有什麼不足,很歡迎大家一起來作更多討論。

Oracle Database in Docker
科技新知
MacauYeah・2023-09-22

雖然筆者之前有提過,Docker並不是萬能,Docker在管理有狀態應用Stateful Application的情況下,只能走單機路線。但因為Docker實在很方便,所以連Oracle Database這類強狀態應用也有出Docker版本。當然,它在預設的情況下,只能在單機下操作。 不過即使在單機操作下,還是有一些跟其他Docker Image有差異的地方,需要特別拿出來聊聊。 假設根據官方的教學,跑起了一個oracle19c的Docker Container。再查看當中的Process,你會發現有一個內部PID為1的runOracle.sh 在Docker中這個PID為1的Process是很重要的,它是判斷整個Container有沒有運行的依據。它就是當初在Docker Image中Entrypoint或CMD指定的那個指令生起的Process。Docker daemon要進行停止指令,要停止container時,也是對著PID為1的那個process來處理。 一般的情況下,如果PID為1的那個process可以無腦地停了、重開,那一切都好辦。但在Oracle Database的情況下,就不適合。因為Database始乎都是有交易概念的Transaction,它的停止並不是殺了process就了事,它還要考慮HDD操作中,有那些可以被考慮為完成,有那些下次要還原undo、重做redo。如果殺了process就等於Oracle 的Shutdown Abort,有機會下次開機會,就會有交易異常而且無法決定該如何操作。 大家需要先進入Docker container,經sqlplus進行必要的關閉Database指令。但此時,PID為1的那個process,其實還在進行中,在Docker 層面,它就像是Docker Container還在正常運行中,只是Database離線了。又因為sqlplus關閉Database並不是馬上有結果的,所以在整體關閉時可能需要串連command。就像

時空幻境 - 熱情傳奇 (情熱傳說) 心得分享
手機‧電玩
MacauYeah・2023-09-19

雖然這遊戲出了有點久,但對筆者來說真的一波三折。玩完後,有一股很強的感概,所以還是寫編評價來比達一下感受。 時空幻境 熱情傳奇 Tales of Zestiria ,其實是在PS3未期推出的作品,當時亦有跨代登陸PS4。那時亦因為推廣PS PLUS 會員,也作為特別作品送給當時的會員,筆者也是當時就下載了這遊戲。但筆者總因為各種關係,玩到一半,就被其他事情吸走了。再回來,總是覺得斷了片一樣,總是想從頭玩,好好看一遍劇情。就是這樣,前十小時的部份,起碼玩了三次。 這遊戲有這麼吸引嗎?即使不斷重來,也想玩? 首先,這遊戲的總評價真的不算特別好,能玩下去,有一部份出於對Tales of 系列的情懷,而另一部份,就基於友善的暫停機制,以及剛好的ARPG動作遊戲難度。 我們先聊一聊那些做得不夠好的地方 劇情 整體來說,本作劇情走捨身成仁的路線,有一些命題,在前期刻意說一半,故弄玄虛,到最後才解答的劇情。中途夾雜一些奇怪的小黃色笑話。總之就整體很慢熱。 戰鬥 系列的傳統,慢慢地在戰鬥中加入新機制。這作也不列表,前期單人模式,前、中期加入BG神依合體,中期加入爆發特技,中、後期加入秘奧義。 但最麻煩的是普攻遊戲中叫作【特技】,它一改傳統,普攻由今集開始,也會隨著使用量有改變。一開始只會有段數差異,隨著使用量增加後,同一個段數配搭不同方向會有新招式。概念是好的,但它對Buffering預按鍵的時機做得不太好,導致初期筆者試不出方向鍵的差異,久而久之,忘了有這些特別的技能可以用。 以上,就是筆者覺得最讓人有機會棄坑的原因。我們再看看那些吸引人的地方 戰鬥 扣除方向鍵的問題後,其餘的機制也很有探索的深度。【奧義】剋制【特技】,【天響術】剋制【奧義】,【特技】剋制【天響術】。因為任一角色只有其中兩類技能,要變換只能通過【神依】能力,但需消耗BG有累積條件的資源來進行。在BG資源短缺的情況下,如何使用特定兩類技能來應付挑戰、決定何時消BG以換得更多優勢的就變得很有必要探討。 它的裝備系統也是對上述這些策略有所影響,不同裝備有額外技能獎勵,有些對BG資源有累積加成,有些對SC回復速度有影響體似魂系的耐力槽。能否通過合成去保留技能優勢,同時保持裝備等級跟得上遊戲進度,也是需要研究研究。 如果大家有看Speedrun,除上述策略需要考究外,還要會不斷測試不同角色招式對控場的差異,玩家可以自由選擇其中一位角色進行人手操控,其他交由AI控制。 整個戰鬥機制,筆者在經過50多小時的一週目主線遊玩後,還覺得有探索的空間。所以對筆者來說,戰鬥機制並不沉悶。 可以暫停的系統 這遊戲,除了在少數的特定CG過場外,所有部份都可以暫停。對於筆者這種,忙起上來三分鐘就會被打擾一次的工作家庭環境,不能暫停的遊戲真的玩不下去。雖然新主機PS5Switch等,對於待機功能已經很成熟。但這遊戲是PS3年代的作品阿,那時制作組已經特意制作暫停工能,而且在非劇情和戰鬥的情況下,還提供任意的快速存檔功能,那可是比同類RPG遊戲,什至是動作遊戲,都要友善。多得這個功能,筆者才能少數地完成在PS平台上的遊戲。 劇情 也多得戰鬥的可探索性,以及可以暫停的系統,讓筆者玩到最後,一些劇情上的疑點也得到了解答。整體劇情並不完美,但也不差,能看完結局,也是一件樂事。其中主角的身世的伏線,處理得不錯。開場故意不提,也沒有讓人刻意深討。但越到後越期,在不經意地變得有越來越有關係,多了一份突如奇來的驚喜。 總結 因為多次重玩,所以筆者對於怎樣可以破關,變得很有執念。或許對比現在的遊戲,老遊戲的聲畫表玩顯得過時,但其內的操作機制,筆者還是很推薦大家去試試。

Git Submodule
科技新知
MacauYeah・2023-09-15

Git Submodule 初次實務上使用submodule來同時管理幾個project的更新。如果有任何理解上的錯誤,請在github中提issue或pull request。 Why Submodule 假設你的團隊中有三個人,A君做A Project,B君做B Project,C君做Main Project。如果可以,A,B各提供已編譯的Binary或Library,給C君直接使用就最好。 但要做到好好管理,A,B都要有自己的發佈系統,即是把Binary上傳到某個分享Repo中,這樣C君就能有條理地通過IDE或Compile工具下載對應的版本。如果是javascript,Repo可能就是npm repo,如果是java,可能就是maven repo。這亦代表A,B君對程式編譯、打包、版本命名等都要很熟悉,不能一輩子都命名為v1.0.0。 如果團隊對這些都不熟悉,C君還有什麼方法呢其實靠著Submodule的功能,C君也可以硬把A,B的Source code取出,做最後打包。 這跟A、B君自己把source code壓縮然後Email寄給C君是有不同的。因為這樣C君並不清楚A,B的git脈絡:C君需要自己做好A、B的版本記錄。想要只回滾A,B的版本普不容易。但經過git Submodule後,C君可以清楚知道現在正使用的是A、B的那一個commit版本。假如有一天,A、B、C三個都更新了,但發現合起來時就跑不動。C君可以保持A、C的版本不變,單獨提取B的某個版本進行測試。當然,你可以說原本Email也可以這樣管理,但始終你不清楚B的版本記錄,Email的日期並不代表Source Code的進度。因為有時候,Bug Fix是針對舊版本的做更新,新功能的Email日期反而比Bug Fix要早 同理,如果大家要連結多個沒有發佈系統的文字資料,也可以利用Submodule。例如筆者正在編輯一本書,當中不同的主題,就是使用Submodule的功能串連起。 Command 馬上看來來Submodule可以怎樣做。 假設你已經知道git 怎樣用,也起了git repo。假設你是C君,進入你的本機repo資料夾內,使用submodule參數。 上面的效果,就是把C君當前repo的狀態,連結到B君submodule當時預設分枝default branch的最後一個commit 中。然後C君在自己的repo怎樣更新,它引用到B君的submodule版本都不會變。 直到某一刻,B君說他加了一個穩定的新功能,請C也連帶更新一下。C君也做好自己的準備後,使用submodule參數進行更新。 注意,如果C君有多於一個submodule,上述指令會全部一口氣更新。另外,如果你覺得B君的最新版本不能用,還是可以針對B君取得特定的版本。

排程執行任務 | Linux Schedule Job
科技新知
MacauYeah・2023-09-07

在Linux底下,crontab是一個最簡單建立Schedule Job的方法。大家用crontab e 就可以進入設定。 # crontab e 1 optrun.sh 其中每個星號,順序代表的是分、時、日、月、星期。上面的例子就是不論何月何日何時,只要每一分鐘就執行一次optrun.sh Singleton Job 問題是,實際情況下,你想執行程式的時間都不一定會少於1分鐘。所以你總是有機會上一個job未跑完,下一個job就開始了。為了保障自已,需要一些參考機制,去決定是否讓job開始跑。 有些情況,可能你會想用job server去做監管,但若只為單線執行的工作,起一個job server還是會增加管理上的複雜性。 最簡單的做法,就是根據不同的程式語言,使用file lock(鎖上)的機制,先上鎖,再做事。但要注意考慮有沒有出現異常情況,令你自己反鎖自己。即是你的process死了,但不懂自己解鎖,這樣以後你也不能再執行了。 在Linux Bash Shell下,就有一個很簡單的做法,就是使用flock指令。用它的最大好處,就是從OS層面下,去鎖上。只要process結束了,不論正常還是不正常結束,都會自動解鎖。 以下例子就是在執行optrun.sh前,先要取得tmprun.lockfile的鎖。如果沒法取鎖,就自動放棄執行後面的指令。 flock n tmprun.lockfile optrun.sh # crontab e 1 flock n tmprun.lockfile optrun.sh Timeout 引入singleton的概念後,其實會引發另一個問題。因為異常的情況,還有機會是不生不死,process hang。所以我們還需要設定一個最大的執行時間,讓你的process在異常的情況下,被強行清走。 例如,ping指令在linux預設是永遠不會自動停止的,可以模擬process hang的情況。如果我們想定時從外部收走ping process,就可以使用timeout指令。以下指令就是2分鐘後殺指ping process。 # in file optrun.sh timeout 2m ping localhost # to check process id, you could use # gt; ps aux grep ping # you will see two different id for ping and timeout 配合errorcode使用,你可能還會在想在timeout時送出一個email通知自已。 # in file optrun.sh timeout 2m ping localhost exitCode=$ if $exitCode eq 124 ; then echo quot;timeoutquot; # enter email alert with timeout elif $exitCode gt 0 ; then echo quot;exit with errorquot; # enter email alert with timeout else echo quot;exit normalquot; fi 配合docker使用,你可能需要考慮signal怎樣傳遞。 在筆者測試的環境中,似乎SIGTERM會被擋,也有可能是SIGTERM太強,它只把前景的docker container run收走,但其內的ping process還在docker daemon中行走。所以最後改用SIGINT,讓docker container run可以好好地把SIGINT傳入其內。 # It seems that docker captured the SIGTERM. Send SIGINT instead # in file optrun.sh timeout signal=SIGINT 10s docker container run rm pingtest c 20 exitCode=$ if $exitCode eq 124 ; then echo quot;timeoutquot; # enter email alert with timeout elif $exitCode gt 0 ; then echo quot;exit with errorquot; # enter email alert with timeout else echo quot;exit normalquot; fi Full demo, github repo cronjobWithDocker