從零開始的 Nextcloud 完整安裝教學

用兩顆外接硬碟組 RAID 1,設定 DDNS、Nginx,並安裝 Nextcloud,以及後續的 PHP 調校與 Redis 快取。

August 7, 2021 · 8 分鐘 · wancat

過早的優化是萬惡的根源

有次我要開發一個規劃時間的演算法,需要將時間切割成一個一個單位做計算,這時普通的作法會是用布林陣列來儲存每個時間點,然而我需要對時間做一些 AND、OR、NOT 的布林運算,我當時突發奇想,假如用 BigInt 來儲存效能和記憶體都會省下不少,意思是將一個整數視作一個布林陣列,每一個位元就代表一個時間單位,這樣相比用布林陣列,足足省下至少 8 倍的記憶體。我心裡覺得這真是太酷了,於是就一股腦開發基於 BigInt 的演算法。 BigInt 由於本來就不是陣列,不論是讀值、改值都相當因難。以讀取第 i 項的值為例,需要寫成: // normal index array[i]; // bigint index const n = 0b10111000; (n >> i) % 2; // ??? 看起來不直觀、可讀性差、又容易出現差一錯誤。debug 時也相當難纏,直接把 BigInt 印出來,會得到一個巨大十進位整數(本來它就是 Big Int 嘛),需要額外呼叫方法將其以二進位顯示,後來我還將其封裝成一個類別,花了好大力氣寫 unit tests、各種 debug function,最後終於將演算法給實作出來了,花了整整兩週的時間(side project 嘛)。 正當我得意於自己的成果時,遭到現實衝擊——我們使用 React Native 來開發 Mobile App,而 BigInt 是新語法,React Native 還沒有支援。我耗費好幾個小時嘗試各種偏方,然而都不得好轉,最後在無耐之下只好將演算法用陣列重寫。原先以為會天崩地裂、再花上一週的時間,然而由於我有非常多的單元測試,我竟然只用一個下午就將整個演算法改寫完了,比我研究如何在 React Native 跑 BigInt 的時間還少,而改寫後程式的可讀性也提升了不少,那效能呢?由於這是個跑在 client 端的演算法,效能根本不重要,使用體驗毫無差別,省下那一點點記憶體也一點用都沒有。 「過早的優化是萬惡的根源」,在不存在效能瓶頸時就做優化,結果適得其反。比起效能,應該以可讀性優先。 此外,單元測試真的很重要。

August 3, 2021 · 1 分鐘 · wancat

在 Python 中實作對話型聊天機器人

當你在開發一個聊天機器人,有時候為了使用者體驗,你不能要使用者用像指令的方式,將所有資訊一次傳過來。舉例來說,若我們要開發一個猜數字遊戲運作如以下: user: guess bot: From what number? user:: 25 bot: To what number? user: 100 bot: Guess a number between 25 to 100 user: 64 bot: too small user: 91 bot: too large …… user: 83 bot: Correct! You spent 6 times to guess this number. 然而,我們在後端通常是「一個請求一個回覆」,如果要將這樣的行為拆成多個 handler 將會是場災難,為什麼?想想要怎麼存狀態,全域變數?資料庫?還是 Redis?每當你多問使用者一個問題,你就得在你的 state schema 新增一個欄位,讓你的程式碼越來越複雜。 接下來,我會告訴你如何用一個非常輕鬆的方式處理對話,讓你只要寫像以下一般的程式碼就能達成。 def guess(self): '''Game function''' min_value = self.ask_number('From what number?') max_value = self.ask_number('To what number?') secret = randint(min_value, max_value) msg = f'Guess a number between {min_value} to {max_value}' counter = 0 while True: counter += 1 answer = self....

July 29, 2021 · 3 分鐘 · wancat

基本收入不能解決貧富差距,又如何?

當我們用「翻轉」一詞,其實就已經隱含了單一的價值觀:有錢就是高社會階級

July 8, 2021 · 1 分鐘 · wancat

Django 將 Stdout 導向 Streaming Response

有時候後端要執行一個時間比較長的任務,而任務內容極為複雜,又容易出錯,因此希望讓使用者看到即時的 console log,讓我們函式中的 print 輸出能即時傳到使用者的瀏覽器。 以下將會以 Django, Thread, Queue 進行實做 StreamingHttpResponse 一般的網頁請求都是一次打包好所有資料,全部傳給使用者,有些情況我們不能等到所有資料準備好才一次傳,而要拿到一些就傳一些,這個時候我們就要使用串流輸出,在 Django 裡,就是使用 StreamingHttpResponse,以下簡稱 SHR。SHR 接收一個 Iterator 作為輸入,因此我們只要實做一個迭代器函式,其中每次 yield 就會由 SHR 傳送到瀏覽器 # Example of StreamingHttpResponse from django.http.response import StreamingHttpResponse def example(): for i in range(5): # Add <br> to break line in browser yield f'{i}<br>' def stream(request): return StreamingHttpResponse(example()) Output (in browser): 0 1 2 3 4 Thread 由於我們的程式需要一邊執行目標任務,一邊串流輸出,因此需要平行化執行。Python 中可以使用 threading, multiprocessing 等方式做平行化執行,本文將使用 threading。 # Example of threading from threading import Thread import time def example(times): for i in range(times): print(i) time....

May 25, 2021 · 3 分鐘 · wancat

減法的藝術

這時我才終於體會了老師口中的「有捨才有得」,若無狠心除去那些無關的枝葉,最可貴的美就會被埋沒。園藝是如此,創作又何嘗不是呢?

April 18, 2021 · 1 分鐘 · wancat

母語者心態

這些方法也許的確有效,但並不是所有人都能做到我們認為輕而易舉或理所當然的事,當帶著這樣的「母語者心態」看別人,就容易將他人的不成功歸因到不夠努力的結果,卻沒想到也許對方根本做不到。

March 19, 2021 · 1 分鐘 · wancat

每日一問:如果世界是個函數

若是每個現在都會對應到唯一的未來,那每個過去也都會導向唯一的現在,因此回推到宇宙的開端,就可以得到一個結論:現在發生的一切都是在大霹靂時就註定了。那我們所謂的自主意識,也全都只是空談。

March 7, 2021 · 1 分鐘 · wancat