潮流特區

最新文章

Git - 持續整合策略 02 | Git - Continuous integration strategy 02

科技新知
MacauYeah・2024-03-14

Night Build 實務操作上的注意點 Night build第一個要注意的問題,就是要確保同一個commit,真的可以重複建設。一般來說,大家的目標只在運行測試,而自動測試不具破壞性,就基本可以重複的。而如果測試當中包含發佈測試版本,那就還要考慮重複發佈有沒有生效或造成附作用。 以Java maven為例,重複發佈測試版本需要遵守特定的規則,版本號需要以SNAPSHOT結尾,這是為讓maven每天都會重新下載它們的包。而沒有SNAPSHOT結尾的,就只會做一次性下載,減少重複下載造成的資源浪費。若真遇著不支援重複發佈的情況,就需要以日期時間做版本號,就像vscode的某些插件,就是以時間截結尾以作為區分。 Night build另一個要注意的問題,就是開發圖隊何時進行下一輪開發,這會決定何時有新的版本號。扣除上述因為工具不支援的而引發的副作用,還要考慮沒有更新而發生的問題。 有個尷尬情況是,團隊在發佈現行版本時,release commit與main有機會是同一個commit(也就是未有進行下一輪開發)。若不斷重複發佈,有沒有變相發佈了一些沒有預期的功能?例如Docker image,官方大力建議每日自動發佈。當底層的image更新後,頂層引用它們的image,也可以重新發佈,保持安全性。但這樣做的問題,就是頂層的同一個版本號,昨日與今日的運行結果也可能不一樣。這對追蹤問題,並不友好。 所以大家做分支整合時,要預先對版本號作好規劃。然後還要留意Night build不應與release commit重疊。版本號大家做好語意管理,再加上alpha / beta / SNAPSHOT等區分Night build版本,應該就足夠了。而commit重疊問題,就要留意開發週期,Night build要麼就比release早一個commit(即在release時,不推進Night build),要麼晚一個commit(即馬上規劃下一個版本號進行Night build)。

Spring Boot 02 - 快速接入Database的選擇: Spring Data JPA

科技新知
MacauYeah・2024-03-08

快速下戴模版 使用Spring initializr,可以很容易就建立一個以Spring boot starter為底的java project。大家可以使用Spring 官網又或是vscode plugin 快速地建立一個maven或gradle project。筆者較為熟悉maven,就以maven起一個範例。 在使用Spring initializr有幾件事必需要指定的: Spring boot version: 3.x.y 或以上 Language: java Group Id: 請選擇有意思的域名,如果你用github,可以選 io.github.yourusername artifactId: 這個範例的名字,例如commandline Packaging type: 本次使用jar,日後若開發web 應用,可以使用war Java version: 17或以上 Dependency: Spring Data JPA, Spring Boot DevTools 這次不像過去順利,因為這裏欠缺了Database連線資料,為了方便測試,我們先在pom.xml加入 h2與spring的整合很好。即使用什麼都不設定,直接運行mvn spring-boot:run,都可以成功執行了。但如果可以,在application.properties加入資料庫設定,會方便日後移植到其他常用的資料庫品版牌。 # src/main/resources/application.properties spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:testdb; spring.datasource.usename=random spring.datasource.password=random 然後我們就可以做靠Spring Data JPA去生資料庫的表 (table)。Spring Data JPA預設使用的是Hibernate。假設,我們有一個表叫APPLE。我們就可以開一個class Apple和一個interface AppleRepo去接它。 // src/main/java/io/github/macauyeah/spring/tutorial/springbootdatabasic/Apple.java @Entity public class Apple { @Id String uuid; Double weight; // getter setter } // src/main/java/io/github/macauyeah/spring/tutorial/springbootdatabasic/AppleRepo.java public interface AppleRepo extends JpaRepository{ // no content here } 注意,因為不同需要,AppleRepo可能繼承不同的XXXRepository,它們大部份都是用來觸發寫入資料庫的指令。而這個也晚除了直接存取Hibnerate EntityManager的需要。 亦因為我們現在用的是h2Database,其實資料表並不存在。我們需要在執行Spring Boot時,同步先建立表,所以在application.properties 加入自動建表的設定。 # src/main/resources/application.properties spring.jpa.generate-ddl=true spring.jpa.hibernate.ddl-auto=update 然後在Spring Boot Context的環境下,可以隨時執行寫入的操作。 @Autowired private AppleRepo appleRepo; public void saveApple() { Apple apple = new Apple(); apple.setUuid(UUID.randomUUID().toString()); apple.setWeight(100.0); appleRepo.save(apple); } Source Code spring boot data basic 因為h2Database只是用作測試用,所以spring-boot執行完,資料庫就會被刪除。而上述原始碼當中,還附上了一些dump sql的方法,至少可以讓大家驗證己儲存的結果。

Git - 持續整合策略 | Git - Continuous integration strategy

科技新知
MacauYeah・2024-02-23

對於原始碼的管理,平常筆者也有在用gitlab的Continuous integration,針對每次提交(commit),都會有自動編譯和測試。但當一個專案中,有很多關聯庫(dependency library)的引用時,光是專案中每個commit 行auto build就不夠用了。更嚴重的是,若然大家有很多微服務micro service,它們的更新不會反映在commit中。 所以定期重跑動動編譯和測試,是筆者認為可以緩解關聯更新的問題,至少可以提高知道問題所在。 筆者先做了一些功課,參考別人怎樣思考Night build (定期重新編譯)這件事。 每次整合新功能到穩定分支(stable branch)之前,都需要做自動測試。 當專案複雜性越來越大,每次自動測試都把全部測試跑一次,就會遇到效能瓶頸。 所以考慮commit時做單元測試(unit test),然後每個固定的時間問隔做整合測試(integration test)。那個固定的時間間隔就是Night build。 而筆者的問題並不是來自於效能瓶頸,而是涉及關聯性更新問題。這些要麼就有是經code base 層面引發關聯性自動試測,要麼就是Night build重複測試。這兩個功能,gitlab都有提供,只是筆者初步構想下,Night build比較易設定。因為要考慮micro service的於沙盒環境的部署,最簡易的Night build只需要一個共用的環境就夠。但也同樣意味著,Night build需要進行多個不同的分支測試。就需要多個不同的環境。 Night build的測時時機也是一個問題,因為測試當下,並不能百份百對應關聯micro services的提交狀況,大家就更需要做好發佈的版本號語意管理。 不知道看完筆者的策略之後,大家又有何看法?歡迎大家一起加入git筆記的編輯。

git 分支整合問題

科技新知
MacauYeah・2024-02-20

不知道大家的開發團隊、專案規模有多大,但只要系統或程式已發佈,同時又要做維護更新,git 庫都至少會有兩條分枝: 新功能 - main / feature 最新的穩定發佈版本 - Release / v1.x.x 最好的情況下,在開發完新功能之前,穩定版本都沒有需要緊急修正的地方,開發者可以專心開發新功能(main / feature)。然而這個情況並不能經常維持。 情況1:有Bug要馬上修正 最常見到的情況,就是穩定發佈版本有瑕疵,可以經過小修小改來止血,由v1.x.x ⇒ v1.x.y,這些可能對用戶來說,是沒有太大感覺的改動。不過對於開發流程,就免不了由v1.x.y整合(merge)回main時,出現修改衝突的問題。 建議 若屬於日後不再需要的改動,不需於整合到main中, 當然什麼都不用做。但若屬於必要的更新,就需要早早整合到main中。整合雖然痛苦,但延後整合沒有好處。以筆者的經驗,每次整合時有衝突,而越早整合越有條件知道該取用自動混合的那個版本。以整合工具的語言來說,就是更容易的作出use mine / use theirs / edit。 情況2: 不同功能之間有衝突 上述情況1,已經算是可控的。主要因為穩定發佈版本都只會接受小修小改,大改都會直接在main中開當為新功能開發。當你有多個很重要的功能在不同時期被提出,而有些功能你沒有信心在下個發佈中提出,你就會選擇以獨立分支來實現不同的功能,最後選擇信心度高、權重也比較高的功能來發佈。這樣的好處是你可以有限時間先完成最必要的功能,但問題是多個功能分支之間,更容易地有衝突,後期也需要很廢心力地整合。 建議 少做資料夾層面的改動,因為git rename的功能並不是萬能的,會令很多git自動選擇版變得不可讀。筆者的經驗,就是錯把後端和前端的資料夾混在一起,令後端的一些重命名影響到前端。前端也因為有重寫的需要,對資料夾結構大改。最後結果就是很多看不懂的git自動選擇版。有一些有選對,但有一些就選錯。 可以做一些事前處理,來減經痛苦。在筆者的資料夾問題情境,在把後端將要整合的多個commit中,挑選最早前沒有命名問題的commit先整合一次。然後前端先手動模擬後端的人工命名,自行commit一次,最後再把後端剩餘的commit再做整合。這個做法不是完全解決問題,但至少可以讓use mine / use theirs / edit更新易理解。 而另一個建議是,縮短發佈週期,逼使其他開發中的功能越早做整合,也逼使每個功能不要做太大規模的改動。如果真的做大規模改動,就要有心理準備要多次重要的整合。 情況3: 多個穩定發佈版本需要同時維護 若然大家面對的工作規模真的很大,同時有多個版運行版本,就如gitlab,每一個月都有一個新功能版本(16.0.x, 16.1.x, 16.2.x,… 16.9.x),但它不會強逼大家更新,對於過去一段時間的功能版本,也會推出安全性更新(前述的x會不斷修正問題)。 這是一個很負責任的發佈模式,不過對於開發者來講就一定很地獄。因為16.0.x的安全更新並不能無痛地整合到16.9.x中,可能每個版本重新人工修改還要來得穩健。 建議 各個分支人工修改可能更適合。最後就是取決於商業政策的考量,到底公司願意為已發佈的功能版本提供多久的支援。就以gitlab為例,其實它也只承諾維持兩三個月前的功能版本。是否會backport到多個月之前的版本,就看問題的嚴重性和backport難易度。 也分享一些筆者朋友的經驗,他們開發的是軟件跟硬件整理的軟件庫。但因為硬件有限制,例如庫的大小、算力的差異,所以最後分支多到爆炸。這也是軟硬整合的痛,問題暫時無解。除非老闆肯放棄市場。

龐大的Docker Logs該如何處理? | 傳統的syslog幫到你

科技新知
MacauYeah・2024-02-02

平常大家在做單機app時,寫log有很多選擇,最簡單就是寫在檔案中。但在docker container裏面,寫檔案時要注意怎樣保留log檔,避免因為重建container時不見了。 docker 大部份官方預設image,都把log導向至stdout和stderr。這是方便docker做管理,也方便大家使用統一的docker logs指令來查看,即使到了Swarm mode底下,docker service logs也是同樣原理,使用差異不大,頂多就是不保證log的實時性。 如果網路延遲不計較的話,最大問題也是logs怎樣保存的做法。預設就是container刪走的時候,logs也會一借走。單機模式下,沿用最普遍的方法寫log的做法不是不可行,只是考慮到在極端情況下,同一個node(節點)中,有可能同時運作同一個service(服務)的多個分身(replica),這裏它們寫檔案時就有機會互相搶佔。 筆者認為,比較合理的是外部提供的服務,例如syslog,把寫檔的操作交給節點的Host OS處理。然後就保證好每筆log都會是一條完整的記錄。 以下就以linux Host裏面的syslog,為大家簡介一下設定的步驟。 設定docker 導向 syslog 把該主機的docker daemon (/etc/docker/daemon.json),設定使用syslog driver,並以特定的方式編寫syslog tag。 { "log-driver": "syslog", "log-opts": { "tag": "dockercontainer/{{.ImageName}}/{{.Name}}/{{.ID}}" } } 無腦設定已完成,重啟docker就可以了。 但為了日後管理方便,能把docker log放進獨立的一個檔案中,會更易找問題。所以我們可以進一步設定syslog。我們以Ubuntu 22.04為例,可以在/etc/rsyslog.d/下增加一個設定檔(/etc/rsyslog.d/*.conf),指定看到syslog tag以dockercontainer為首的記錄,都要獨立抽出來。 # file: /etc/rsyslog.d/51-docker.conf :syslogtag,startswith,"dockercontainer" -/var/log/dockercontainer.log 為免有檔案權限問題,手動指定檔案的所有權後,才正式重啟syslog。然後所有相關記錄都會寫在/var/log/dockercontainer.log 滾滾滾滾滾動的log檔 檔案一天一天地長大,如果可以,還是自動清掉太舊的記錄為妙。Linux Syslog,通常也會配著logrotate使用。 筆者亦以Ubuntu 22.04為例子,做了個最簡單的自動滾Log功能。目標就是當log檔案大於1M後,就要重開log檔。舊的log檔最多保留7份,多了就刪掉最舊的。 # file: /etc/logrotate.d/rsyslog-dockercontainer /var/log/dockercontainer.log { rotate 7 size 1M missingok notifempty compress delaycompress sharedscripts postrotate /usr/lib/rsyslog/rsyslog-rotate endscript } 加了設定後,什麼都不用重啟,因為它是Ubuntu 的排程動作,到執行時就會以最新的設定檔執行,詳見/etc/cron.daily/logrotate. 有需要手動測試的話,需要手動呼叫/usr/sbin/logrotate。加入-d參數後,會被視為debug mode,這是官方的說法,但因為debug mode沒有執行效果,更加像是linux中常見的dry run mode。

Steam Deck 也可以作為文字創作

科技新知
MacauYeah・2024-01-23

之前筆者就介紹了,如何使用Steam Deck作為程式開發機使用。這可能對於一般讀者來講不太常用,更常用的是做一些文書處理。筆者最近也拿著Steam Deck,也一步步地補充文書處理所缺少的軟件,正式踏入Steam Deck日常之路。 如果你沒有對系統做過任何更改,在桌面模式中,只要打開「Discover」,輸入後逐的軟件的唯一package name,就可以找到相關軟件。 但如果你像筆者之前一樣,加了homebrew等第三方系統,可能所有軟件都需要在terminal中,經過指令sudo flatpak install PACKAGE_NAME。 Chrome 唯一碼: com.google.Chrome 系統預設瀏覽器只有Firefox,不習慣的話可以另外下載Chrome。有了Chrome,至少所有的雲端文書軟件都可以用,想用Google Doc也沒有問題。 中文輸入法:Fcitx5 + Rime 唯一碼:org.fcitx.Fcitx5 唯一碼:org.fcitx.Fcitx5.Addon.Rime Steam Deck原本有自帶的輸入法,但只適用於螢幕虛擬鍵盤使用(即使用Steam key + X,打開虛擬鍵盤),而實體鍵盤就無法轉輸入法了。這時就需要Linux上的Fcitx5和Rime了。安裝很簡單,之後還要設定一下。 首次安裝後,在啟動器(桌面左下角)搜㝷及啟動 fcitx5,然後在右下角就會見到有個新的鍵盤圖示出現。 按鍵盤圖示,滑鼠右鍵,點選configure,把Rime 加入Fcitx裏面,然後Apply → Close 然後按鍵盤圖示,滑鼠左鍵,應該就會切會成中文輸入法了。這時原本的鍵盤圖示會變成中文輸入法的圖示(或者你經Ctrl-Space也可以) 最後對著中文輸入法圖示,再滑鼠右鍵,可以選擇不同的中文輸入法,例如拼音、注意、倉頡等。 有了輸入法,有了瀏覽器,世界已經都是你的了。 下載器 JDownloader 唯一碼:org.jdownloader.JDownloader 它可以用來下載大部份隱藏文件,例如YouTube video / audio 。但需要注要,首次下載JDownloader 後,還要經過軟件內部更新,否則不能使用。(就像很多手遊,下了主程式後還要下更新檔) 其他 如果你不是長期有網絡,還需要真離線版文書處理器,還可以看看LibreOffice,WPS Office。但這些都不能保證跟windows office 百分百轉換,可能還是使用雲版的Microsoft office 365還要實際。

Spring Boot 01 - 萬物始於Spring boot context

科技新知
MacauYeah・2024-01-16

Spring Boot 01 - 萬物始於Spring boot context 筆者早些時候向一位朋友討論,為何Java那麼不受歡迎。朋友一句就回答,Java煩爆,沒有人會喜歡。 老實講,Java在句法上,實在囉唆。但以筆者的經驗,即使使用其他語言和開發框架,在實戰到一定複雜程度下,其實也一樣煩爆。 而現在的Java框架中,就以Spring boot的入門門檻低。筆者從Spring boot 1.x用到現在的3.x,也真的感受到更多的簡化,所以筆者也加入一起推廣Spring boot的行列。筆者將會通過一系列最小的可執行程式,為大家講解Spring在Web和資料庫上的應用。 所以現在就不廢話,馬上開壇作法 快速下戴模版 使用Spring initializr,可以很容易就建立一個以Spring boot starter為底的java project。大家可以使用Spring 官網又或是vscode plugin 快速地建立一個maven或gradle project。筆者較為熟悉maven,就以maven起一個範例。 在使用Spring initializr有幾件事必需要指定的: Spring boot version: 3.x.y 或以上 Language: java Group Id: 請選擇有意思的域名,如果你用github,可以選 io.github.yourusername artifactId: 這個範例的名字,例如commandline Packaging type: 本次使用jar,日後若開發web 應用,可以使用war Java version: 17或以上 之後就不用選了。若你經官網起範例,你會得到一個zip檔,下載後解壓縮。若你使用vscode插件,最後插件會叫有一個位置儲存。它們都是最後也是會得到同一樣範例Java project。 你使用Vscode,Intellij打開,IDE都會自動辨識到它是java maven project,同時會顯示java和maven結構。道理上你用Intellij 應該可以無腦開始編譯(Community 或Ultimate版都可以), Vscode有安裝Extension Pack for Java也會開始自動編譯。不想麻煩,也可以試用Github Codespaces - java。Github Codespaces其實就是一個雲上的vscode,經網頁可以連到Github VM內的vscode,所以它也會有齊Extension Pack for Java等插件。 筆者最後也會上載已完成的範例,它也可以在Github Codespaces上以Java執行或繼續開發。 打開project中的pom.xml,它為我們添加了兩個很重要的lib org.springframework.boot spring-boot-starter ... ... org.springframework.boot spring-boot-maven-plugin spring-boot-starter是重中之重,它定義了怎樣動態地設定日後的其他lib,它是讓我們可以無腦設定的一個關鍵。(但若大家有很多客制化的設定,就要返撲歸真地逐個lib叫起)。 maven在預設情況下,只會負責編譯和打包目前的project原始碼。所有相關依賴(就是xml中的dependency),並不會自動包起。而spring-boot-maven-plugin,就是幫我們把相關依據都包在一起,讓你的jar可以獨立行起來。 註: 若大家在開發lib jar,並不是一個獨立執行的jar,也就是原始碼上沒有main函數,大家就不應該引用spring-boot-starter和spring-boot-maven-plugin。 我們繼續看其他原始碼,整個資料夾就像以下那樣。 . |-- HELP.md |-- pom.xml `-- src |-- main | |-- java | | `-- io | | `-- github | | `-- macauyeah | | `-- springboot | | `-- tutorial | | `-- commandline | | `-- CommandlineApplication.java | `-- resources | `-- application.properties `-- test `-- java `-- io `-- github `-- macauyeah `-- springboot `-- tutorial `-- commandline `-- CommandlineApplicationTests.java CommandlineApplication是我們有main函數的java class。我像可以經過IDE運行main又或者下指令mvn spring-boot:run來執行。 正式開始我們的Commandline開發 我們在CommandlineApplication.class中,加入新的程式碼,實現ApplicationRunner和它的函數run。 package io.github.macauyeah.springboot.tutorial.commandline; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; // other import @SpringBootApplication public class CommandlineApplication implements ApplicationRunner { static Logger LOG = LoggerFactory.getLogger(CommandlineApplication.class); public static void main(String[] args) { SpringApplication.run(CommandlineApplication.class, args); } @Override public void run(ApplicationArguments args) throws Exception { args.getOptionNames().stream().forEach(optionName -> { LOG.debug("option name:" + optionName); args.getOptionValues(optionName).forEach(optionValue -> { LOG.debug("option values:" + optionValue); }); }); LOG.debug("program end."); } // ... 這個run函數很直白,就是更好地演譯main中的String[] args。 但大家還要看清楚,這個main並沒有直接執行run。其實它是靠SpringApplication.run及@SpringBootApplication,跑一堆自動設定,最後因為傳入CommandlineApplication.class是一個Spring 可以處理的ApplicationRunner,所以才呼叫它的CommandlineApplication.run。 換個講法,如果今天做的是web應用,傳入去的就會是SpringBootServletInitializer,這個SpringBootServletInitializer也不一定跟main是同一個class。 如果大家有興趣,可以經過反編譯器,點入@SpringBootApplication看它的原始碼,你就可以看到它其實代表了很多自動化的東西。如果我們只做一些在同一個模組下生效的事情,《自動化》極大地降低了大家入門門檻。一般來講,如果大家不在意程式碼的複用度,比較少機會自行設定,自動化已經很有用。而隨著系統規模增加,多模組就慢慢地顯得重要,在大家了解完基本的Spring後,著者再從測試用途test case入手,為大家介紹如何手動設定。 Source Code Commandline Application

Spring Boot - Maven Cheat sheet

科技新知
MacauYeah・2024-01-12

基礎 刪除所有結果,全部重新編譯 mvn clean compile 跑起用Spring boot寫的main class,運行Spring boot context。 mvn spring-boot:run # or mvn clean compile spring-boot:run 執行測試用例,預設只會測試test資料夾下以某些命名規則的class(例如class名以Tests或Test結尾的class,其他命名規則筆者未有能力一一驗證) mvn test # or mvn clean compile test 多Profile、多組件、多測試 使用-P指定編譯時的選用pom.xml中的project.profiles.profile參數。也可以用此來傳遞到spring profile,使得編譯後的spring war預設選擇特定profile。 mvn clean compile -PmvnProfile # or mvn clean compile spring-boot:run -PmvnProfile 使用-pl限定mvn指令只對某個子組件生效,但有時候子組件之間也有引用關係,所以需要再額外加上-am參數(--also-make) mvn clean compile spring-boot:run -pl SUBMODULE_NAME -am 使用-Dtest=限定只執行某個class的測試用例,或單個測試函數。(可以無視class名的命名規則) mvn test -Dtest=TEST_CLASS_NAME # or mvn test -Dtest=TEST_CLASS_NAME#TES_METHOD_NAME 若屬於多組件情況下,其他子模組找不到同樣名稱的測試,會測試失敗。需要再加上-Dsurefire.failIfNoSpecifiedTests=false mvn test -pl SUBMODULE_NAME -am -Dtest=TEST_CLASS_NAME -Dsurefire.failIfNoSpecifiedTests=false # or mvn test -pl SUBMODULE_NAME -am -Dtest=TEST_CLASS_NAME#TES_METHOD_NAME -Dsurefire.failIfNoSpecifiedTests=false 打包 在本機電腦中,把java變成jar或者war。通常用於自行發佈的環境中。 mvn package 有時特定Profile沒法成功執行測試用例,或者你認為有些測試問題不影響使用,需要跳過package中的test。 mvn package -Dmaven.test.skip=true # won't compile test folder mvn package -DskipTests=true # compile, but won't run 例外情況 強行把一個第三方jar,種到本機電腦中的.m2/repository # copy from https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html mvn install:install-file -Dfile= -DgroupId= -DartifactId= -Dversio

找一個可以私有化的協作平台

科技新知
MacauYeah・2023-12-19

在現今這個網路為王的年代,大部份文書等編輯工作都可以在Google Drive, One Drive那邊多人協作。唯一的問題是,你是否考慮資料保密問題。 一些開放資料,放在雲端上,故然無問題;個人用資料,就自己為自己負上保密責任。但作為一家公司,把自家客戶的資料放在Google Drive、One Drive上,你又會否覺得足夠保密? 不放在這些協作平台上,改為自購一個NAS File Server,把共享檔案都放進去,這樣又足夠方便嗎?現在File Server最大的問題,是無法提供同時協作編輯的功能,想在同一個檔案,多人同時更新不同的部份,是不可能的。 Etherpad-lite 如果大家只需要一起寫文字稿,可以試用Etherpad-lite https://github.com/ether/etherpad-lite 。 筆者試用過,它提供實時協作,其他人的更改可以即時顯示,也有一些基本的排版功能。缺點是lite版沒有好好處理大量的資料問題,一次過複制貼上大量文稿的話,會出現網路問題。 NOCODB 如果大家需要的是試算表,可以試用NOCODB https://github.com/nocodb/nocodb 。它強大的地方,是可以匯入CSV, Excel,做欄位搜尋。老實講,這些功能,對於一個IT人來說,隨便安裝一個資料庫,例如:MySQL、 MSSQL, 都可以做到匯入結構性資料,並供多人操作資料。但對於普通用戶來講,要學會操作SQL語言,實在有難度。而經過nocodb之後,可以把MySQL等轉化為常見的試算表型式,實在驚喜。而且,它也能提供一些簡單的填表方式(Google Form)

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.add(car); } } 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().filter((car) -> { 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 = filterCarsByWheelsSize(tempCars, 4); return passTestCars; } private static List filterCarsByWheelsSize(List 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.add(car); } } return passTestCars; } 上述ex3是一個有效的改進。如果大家不計較傳入參數的先後順序及交互影響的話,就已經很足夠。 但如果大家對於多參數的解讀又怎樣? private static List someotherfunction(List 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 ArrayList(4); cars = cars.stream().filter( filterCarByWheelSizePredicate(wheels) ).toList(); return cars; } private static Predicate filterCarByWheelSizePredicate(List wheels){ return (car) -> { 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

澳門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教育機構,希望可以提供更多的網上資源,讓學生可以解放地點和機器的限制。對於現在的IT/Software的從業員,希望大家都可以擁抱Docker/Linux Container,這樣才能最低成本地試用新事物。