by:陳澤榮 (timothychenpc@gmail.com)
日期:0326-0403
前情提要
這次的開發日誌,距離上次也停更了很久,主要就是因為我們原訂要在二月結束的專案,在最後(
2/28
跟客戶確認的時候)發現因為最開始的需求確認的流程有出一些問題(太籠統),而我們的系統和介面也都是根據客戶的需求進行設計的,所以這也就直接的導致我們的專案內容有很多都需要進行修改,基本上算是要重做啦,然後就停了一段時間休息一下,在這段時間裡我也去學了很多的東西,也重新思考和構思了整個專案後端的架構和設計。所以最後真正開發的時間才能壓縮的比較短(大概一周,十幾小時醬),由此可見架構的重要性!這邊架構的部分我主要是圍繞幾個部分去畫的:路由管理、物件、頁面的從屬、和資料流向
那如果有要畫伺服器或者網站架構的話也可以採用類似的方式從多個面向切入去分析。 其實最主要的一點就是在想架構的時候要自己在腦袋裡面先跑過很多遍,重複去思考,修改錯誤之類的。
用頁面區分的話主要可以分為:
- 登入 /
- 首頁 /home
- 用戶管理 /customers/
- 完成 /finish
- 延期 /delay
這幾個主要的頁面,登入的話就是基本的登入驗證、然後之後的所有頁面也都是需要登入後才能訪問的。
登入功能
要實作一個基本的登入功能其實沒有很難,只是這邊我是採用物件的方式處理所有用戶操作
像是:
login
登入校驗
logout
註銷cookie
start_session
發放cookie
register
後端進行註冊
整體來說這邊採用的登入就是最基本的
cookie-based login
只是在flask
中有將cookie
使用密鑰進行加密,然後這個加密的cookie
就被叫做session
(注意:這裡的session
不是會話的session
,這裡是flask
這個框架實作的cookie
的一個名稱)。然後關於密碼安全性的問題,在數據庫中都是
sha256
的形式進行儲存,然後驗證的話也很輕鬆,就直接比對哈希值就可以(我真的覺得當初發明這個方法的人真的很天才,尤其是在我在看過0知識證明之後)start_session
的部分其實也就是在登入驗證之後將cookie
存入使用者的瀏覽器首頁
這個首頁就是登入後的功能目錄可以索引到完成、延期和用戶管理。
用戶管理
這個部分應該就是整個最複雜的部分了,這個路徑下需要可以:
- 顯示所有的用戶
/customers/
- 查看下個月的用戶
/customers/next_month/
- 查看這個月的用戶
/customers/this_month/
- 依照名稱、ID、地址等搜索用戶
/customers/?key=&value=&type=
- 顯示個別用戶
/customers/<id>
- 修改個別用戶的資料
/customers/<id>/edit
- 刪除用戶
/customers/delete
- 新增用戶
/customer/
用戶管理的主頁面
當訪問
/customers/
的時候會先將所有的用戶都顯示出來(後端渲染),然後如果點擊下個月就會訪問/customers/next_month/
,本月就是/customers/this_month/
,然後搜索的功能就會使用AJAX
,訪問到/customers/
並使用query string
傳遞參數到後端,然後在網頁載入後將資料載入。搜索的
query string
主要的參數有三個:key
搜索用的鍵
value
鍵對應的值
type
決定返回值的型態(如果是json
就會回傳純資料,其他情況就是完整網頁)
這邊我比較想講的就是針對地址的搜索功能,這邊的話我主要支援的就是針對縣、市、區三級的搜索功能,不管輸入的縣市最後有沒有加上縣市,都會在後端自動加上,再通過正則表達式在數據庫中進行搜索
這邊的渲染就是單純採用
jinja2
在回應請求的時候進行的渲染訪問個別用戶
在用戶管理那邊點擊用戶的名稱(每一個名稱都是一個超連結),就會跳轉到該用戶的個人頁面
用戶的個人資料頁主要會分為兩個部分:基本資料和記錄卡。然後只有基本資料是可以進行修改的,然後點擊編輯就會進入修改頁面
然後進行修改(每一個輸入框預設都會是原本的資料),同樣會藉由後端針對輸入的資料進行基礎的驗證
刪除用戶
這邊是在彈窗確認刪除之後就會向後端發起請求刪除用戶,然後重新渲染頁面
新增用戶
一樣是採用彈窗進行新增,然後一樣有進行後端驗證,但是因為是彈窗的關係比較難返回結果,所以後來就是由後端發起彈窗“新增成功”和“新增失敗”來告知使用者目前新增的情況
完成功能
完成的功能主要就是紀錄用戶飲水機的保養狀況,以及下一次保養的時間。
那這邊的內容我就是採用表單的形式通過
post
請求進行傳遞,至於表單資料的驗證的話,這次主要是採用後端驗證(然後這邊的表單驗證我使用wtforms
實作的)。然後為了能夠鎖定特定的用於更新保養狀況,就需要選擇一個用戶,我試過很多的方法,像是直接下拉式選單等等,但是我們的
4000
筆資料一灌進來就會非常的卡頓。所以後來我就開始嘗試和使用AJAX
技術,將搜索用的key
和value
通過query string
給到後端,再用Javascript
將結果放入搜索結果(是一個readonly
的input
),而基本上只有在搜索結果顯示found
的時候這一項的驗證才會通過。那這邊會採用
AJAX
是因為如果需要載入的資料量大的話,網頁不會當(就是等待資料載入的時間網頁是可以正常交互的,但是一般渲染完整html
就不行),所以AJAX
其實就是為了能夠在這裡提供更好的用戶使用體驗然後這裡的
AJAX
我是用EventListener
的change
事件去監聽value
那格輸入框的值有沒有改變,如果有改變就想後端發起一次請求重新確定該使用者的狀況。延遲功能
這部分大致上也跟完成功能很類似,一樣使用
AJAX
去確認是否存在後端檔案結構:
Project
__
init__
.py
用於建立封包
decorators.py
裝飾器
forms.py
表單驗證物件
model.py
物件模型
db_test.py
數據庫測試
static
靜態素材的資料夾
templates
html
的資料夾
routes.py
路由管理
app.py
伺服器物件decorators.py
這邊用到的裝飾器其實目前也只有兩個(
login_required
和time_it
)前者就是我用來限制沒有登入的人無法訪問頁面的,後者的話就是寫了一個裝飾器去計算每一個函式的執行事件(在之後針對速度進行優化的時候會比較有幫助)
model.py
這邊的話我主要就是定義了兩個物件,
DB_Model()
和User()
主要就是分別處理所有有關數據庫的操作和使用者登入登出等處理。只不過DB_Model()
的話我使用的都是實例化成db_model
的版本。那我會這麼注重物件也是因為這種多檔案的結構,使用實例化的物件在檔案直接傳遞是最有效且最實際的。關於優化
安全性
這部分應該會比較之後進行考慮,之後可能增加更多的加密方像是
AES
或者RSA
這些,針對用戶數據進行加密。速度
目前主要會有速度問題的頁面也就只有
/customers/
和/customers/this_month/
還有/customers/next_month/
這幾個頁面(不包含搜索功能),因為是通過jinja2
用循環渲染的,而在資料量大的時候(大概4000
筆),載入會有卡頓,然後一開始懷疑是mongodb
那邊因為要緩存所有的資料(每一個用戶的id,name
以及其他不必要的資料),所造成的延遲,所以後來修改了search()
在訪問/customers/
的時候4000
筆資料每個都只會載入id
和name
,理論上很久可以節省很多的資源和時間。但是時間的時間的優化幅度好像並不大所以後來就開始懷疑可能是因為過度依賴
jinja2
進行大量渲染,以及傳送超大html
所造成的時間所導致延遲。而這幾個頁面目前也都確實沒有使用
ajax
獲取資料,所以會導致沒有完全載入的時候網頁是不能動的。後來的想法就是將這幾個頁面也一起統一使用搜索的AJAX
。代碼
這部分的主要著重在代碼的可讀性、擴展性等,跟代碼風格和思考模式比較有關的部分。再加上我個人又極其討厭重複的代碼,所以應該之後會再針對一些結構類似的代碼進行優化。
心得:
這次的開發過程跟上一次是完全不一樣的體驗,上一次在開發時候因為沒有那麼詳細的架構和也沒有提前思考物件之間交互的設計,所以導致整個後端開發的週期會拉的很長,因為在每一次寫一個功能的時候就還要去想會不會影響到其他的功能,然後每一個功能要怎麼交互;或者就是都不管,直接實現單獨的功能,然後最後合併就很頭痛。
為什麼會這樣那?
因為本身設計的時候就不是用一個整體去進行設計的,自然之後要合併就會非常的困難(就好比要做一個拼圖一定都是畫好圖形再切成一個個小塊,而不會東做一個小塊,西做一個小塊最後根本拼不起來)。
所以這次在重啟開發之前的時候就是我陸續構思和思考整體架構的時間,而最後畫出來的架構圖也就相當於之後施工的藍圖,有了藍圖之後敲代碼就會很快。而且基本上這次的開發都沒有像上次在寒假有那麼多完整的時間可以進行開發,但是這次因為有了藍圖所以整體開發的速度和效率比上次快很多,每次只要著重開發其中其中的一個功能就可以,而會不會影響到其他的功能早在一開始規劃的時候就想好了。
我覺得基本上自從
2/16
跟巨耀資訊對談的時候,就讓我開始對架構設計的重要性完全改觀了,也意識到了架構才是決定整個專案走向的關鍵。雖然這個專案作為我們團隊的第一個專案,一開始的時候有各種的問題,導致我們甚至都要重做,但是在整個過程之中我還是學到了很多的東西,而我利用這次重做的機會重新思考了架構設計的意義,也重新的開始設計和架構整個網站,也讓我們開始意識到確認需求對於假案這件事的重要性。過程中一定有覺得很幹的時候,但是終於到最後了,終於快要可以結束這個專案了,不管怎麼說,這次的專案跟之前我做的專案性質上差異很大,也算是我們團隊的一個里程碑吧哈哈,而且前端雖然還有一些可以改進的地方,但相對於上次的進步也真的很大。
然後就是我感覺最近我經常會關注在一些寫
code
中比較玄學的部分:像是架構、Design Pattern
這類的,因為我覺得寫程式的重點應該不是針對單一功能的實現(因為光是code pilot
就可以實現單一功能),而是針對整體的架構設計和協調,含有更多個人的成分在裡面,而我覺得這也就是寫程式在未來最主要的競爭力,也是AI
比較難以掌握的。然後這次因為程式檔案越來越大(
zip
都有15mb
)所以azure
的免費方案完全抵擋不住我的commit
轟炸,然後我的配額也就消耗的十分的快,然後到後面要測試根本就沒有辦法測,然後我一氣之下就直接催到B1
了(好在有一個月的免費試用期),也就可以開始享受不會關機的伺服器體驗了。但是有一點我還是搞不懂,就是
azure
的terminal streaming
竟然沒有包含標準輸出流,也就是我基本上開了streaming
也只能看到報錯,其他的print
完全就看不到,所以在debug
的時候就會有一些障礙。最後附上一張
Github
的活動紀錄