# 面試題 [![hackmd-github-sync-badge](https://hackmd.io/wZw69ltzTJWyi2Rc4UjDQA/badge)](https://hackmd.io/wZw69ltzTJWyi2Rc4UjDQA) ## Python ### Python特性: - Python是一種解釋型語言,表示Python不需要在運行之前進行編譯,它是邊運行邊解釋的 - Python是動態類型化的,所以不需要聲明變量類型 - Python中函數是一等對象,意味著它們可以在運行時動態創建,能賦值給變量或者作為參數傳給函數,還能作為函數的返回值 - Python運行速度通常比編譯語言慢。但Python允許包含基於C的擴展,所以瓶頸可以被優化掉 ### Python引號: - 單個單、雙引號都是用來表示字符串 - 三單引號一般用來輸入多行文本 - 三雙引號一般用在類里面,用來註釋類 ### Python垃圾回收機制: - 回收計數引用為0的對象,釋放其占用空間 ### Python實例化class的執行順序: 1. 調用type類 -> 調用內置的元類mateClass -> 調用__new__方法將類實例化 2. 實例將會初始化自己的類變量 3. 進入構造方法__init__,並初始化自己的實例變量 ### Python函數參數: - 位置(必選)參數: - def foo(x, y) - 默認參數: - def foo(x, y=10) - 默認參數(y)要放在必選參數(x)後面,且默認參數不要設為可變對象(可先用None代替) ```python def add_end(L=None): if L is None: L = [] L.append('END') return L ``` - 可變參數(arguments): - def foo(x, y ,*args) - 關鍵字參數(keyword arguments): - def foo(x, y ,**kwargs) - 命名關鍵字參數: - def person(name, age, *, city, job) - 命名關鍵字參數需要一個特殊分隔符*,*後面的參數被視為命名關鍵字參數 ### 物件導向程式設計(OOP)、面向對象: - 目的:使程式碼的維護和擴充更容易,且更容易閱讀理解程式碼邏輯 - 三大特性: - 封裝: 把相同類型的屬性和方法封裝到類中,這樣可以簡化編程,使用者也可以僅通過外部接口來調用,使程式容易模組化 - 繼承: 繼承就是子類繼承父類的特徵和行為,使得子類對象具有父類的實例和方法, 這樣可以減少重複性代碼,且彼此的耦合度會較低,靈活度也較高 - 多態: 不同的(子類)對象調用相同的(父類)方法,產生不同的結果,可以增加代碼的外部調用靈活度 簡單的說就是呼叫同名的方法時,會得到不同的結果 ### lambda 表達式: - 通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數 ```python max = lambda m, n: m if m > n else n print(max(10, 3)) # 顯示 10 ``` ### mutable/immutable: - 是指變數被賦值以後,值可不可以改變。以list來說,li = ['a', 'b'],對應到內存的一個id位置;然後再讓li[0] = 'c',這時li還是指向同一個位置,表示這個列表這個type就是可變的 - 可變:list, set, dict, array - 不可變:數值, str, bytes, tuple ### list和array比較: - list: 方便,可以容納不同的數據類型,但較慢且也要耗費更多得記憶體空間 - array: 只能容納一種數據類型,較快也較省空間 - 一開始陣列內部的型態定義就定義好了,所以不會需要每次都到底層的去做比對 - 因為array是直接儲存數據而非指針,所以相較於list還要去遍歷所有指針會快很多 ### dict和list比較: - 字典的查找速度比列表快很多,但也因此要耗費較大的內存 - 原因:dict和set都是由hash和散列表來實現的。 查找時會通過基層的演算法用hash(key)進行匹對, 如果為空,表示沒有這個值。 如果不為空,且這個值的key為我們要找的,則成功並返回。 如果不為空,但這個值不是我們要的,那就繼續找這個key會存的下一個位置,直到找到我們要的值或為空為止。 - 字典和集合是無序的,列表是有序的 - 字典查找和插入的速度很快,且不會隨著key的增加而變慢;列表查找和插入時間會隨著元素的增加而增加 ### tuple和list比較: - 兩者最大的差異就在於元組是不可變的 - 元組佔用空間較少,也可以當作字典的key做使用,且具名元組可以理解為元組的增強版本,它為元組中的每個元素都賦予了含義,從而增強代碼可讀性 ### json和字典dict比較: - json是一種輕量級的數據交換格式;dict是python中的數據類型 - json的字符串強制使用雙引號;dict則是單、雙引號都可以 - json的類型是字符串,只是是按照key:value鍵值對格式定義 - json的key可以是有序、重複的;dict的key不可以重複 ### Linked-list和Array陣列(c++)比較: - 陣列使用一連串的記憶體位置,因此可以透過array[index]直接存取資料,但相對的,若要在陣列中加入或是刪除元素,則需要大量的資料搬移 - 鏈表的資料則散落在記憶體各處,加入或是刪除元素只需要改變pointer即可,但相對的,在資料的讀取上比較適合循序的使用,且無法直接取得特定順序的值 ### 字符串格式化(%和.format的區別): - %在於使用時更為方便快速 - format較為靈活與強大,可以做到格式限定符(比如:填充、對齊、精度等) ### Python多線程: - Python有一個多線程包threading,可以使用多線程來加快你的代碼。但是Python有一個叫做GIL(全局解釋器鎖Global Interpreter Lock)的構造 - 它限制了python同一時間只能有一個線程執行,所以多線程們實際上只是輪流使用相同的CPU內核 - 對於IO密集型操作:在等待操作系統返回時會釋放GIL;再比如爬蟲因為有等待的服務器的響應時間,可以利用多線程來加速 - 對於CPU密集型操作:只能通過多進程Multiprocess來加速 ## SQL ### SQL索引原理比較: - HASH: - Hash索引僅僅能滿足等於(=)、在其中(IN)和不等於(<=>)之查詢,不能使用範圍查詢 - 因為Hash索引是利用Hash值來比較,所以它只能用於等值的過濾,不能用於範圍的過濾 - 且因為經過相應的Hash演算法得出的Hash值的大小關係,跟Hash前原值的大小關係並不一定相同,所以也無法排序 - Hash索引不能利用部分索引鍵查詢 - 對於組合索引,Hash索引在計算Hash值的時是組合索引鍵合併後再一起計算的,而不是單獨計算Hash值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash索引無法被利用 - BTREE(二元樹): - 是一種將索引值按一定的演算法,存入一個樹形的資料結構中,每次查詢都是從樹的根節點(root)開始,依次遍歷節點(node),獲取葉節點(leaf)。 - 選擇: - 當需要做到排序和區間查詢的,只能用B-tree,而對於欄位相對來說唯一值較高,且都為單欄位查詢的,更適合選取hash。 - 因為當Hash索引遇到大量Hash值相等的情況後效能並不一定就會比B-Tree索引高,所以hash比較適合unique的字段。 ### SQL索引: - 索引是數據庫的搜索引擎使用,能減少讀取的消耗,並以此來提升 SELECT 語句的查詢效能 - 索引類型: - 聚(叢)集索引: - 聚(叢)集索引將資料表或檢視中的資料列依其索引鍵值排序與儲存 - 聚(叢)集索引決定了資料的儲存形態,所以一張表上只能有一個聚集索引 - 如果資料表沒有任何叢集索引,它的資料列就儲存在未排序的結構中,這個結構稱為堆積 - 通常會建立在PRIMARY KEY上 - B-Tree結構 - 非聚(叢)集索引: - 資料排序不會受非叢集索引影響(是根據聚(叢)集索引) - 非叢集索引有一個與資料列完全分開的結構 - 非叢集索引包含非叢集索引鍵值,而每個索引鍵值項目都有一個指標,指向包含索引鍵值的資料列 - B-Tree結構 - 用比喻來說,非聚(叢)集索引會比較像是書籍的目錄頁 - 兩者比較: - 叢集索引插入資料時速度較慢(時間花費在「物理存儲的排序」上,要找到對的位置進行插入) - 查詢資料速度: 叢集索引 > 非叢集索引 - 非叢集索引建立的先後順序並不是很重要,因為它們不會互相影響也不會對改變資料表中實際資料的排序,但是建立叢集索引會影響實際資料排列,也會影響已建立的非叢集索引 ### SQL中的where和having差異: - WHERE用於在分組之前過濾;HAVING用於在分組後排除記錄 - WHERE子句不能包含聚合函數;HAVING可以(因為WHERE運行順序在聚合函數之前) - WHERE子句在做篩選時會用到index(索引);HAVING則只是做一個表掃描(所以在兩個都能用的情況下選WHERE,因為效率較高) ### SQL SELECT查詢語句執行順序: - FROM:需要從哪個資料表檢索資料 - JOIN:合併表 - ON:合併表的條件 - WHERE:過濾表中資料 - GROUP BY:將上面過濾出的資料分組 - 聚合函數(AVG): - HAVING:對上面已經分組的資料進行過濾 - SELECT:檢視結果集中的哪個列,或列的計算結果 - DISTINCT:移除相同行資料 - ORDER BY:按照什麼樣的順序來檢視返回的資料 - LIMIT:返回幾筆資料 ### SQL和NoSQL比較: - 兩者皆有事務處理—保持數據的一致性 - NoSQL有較快的讀寫速度,當有需要支撐海量的數據和流量時NoSQL較適合 - NoSQL擴展簡單,因為不用像SQL表跟表之間還有關聯 - SQL數據更新的開銷很小,因為都彼此關聯著 - SQL維護資料較容易,且彼此間可以通過外鍵來保持數據的完整性 ### ORM是什麼? - 這是一種用於實現從物件資料到關聯資料的存儲對映的程式設計技術,將資料庫操作用物件導向的形式來呈現 - 對象(Object):表示面向對象語言中的對象,EX:Python - 關係(Relational):表示你正在使用的RDBMS數據庫(關係數據庫管理器系統),EX:MySQL - 映射(Mapping):表示前面兩個部分之間的橋接和連接,即透過對象和數據庫連結 ### Django_ORM優化: - 無優化: - 代碼: ```python book_list = models.Books.objects.all() for book in book_list: print(book.publish.name) ``` - 造成速度慢之原因: 因為Django ORM的Queryset查找是屬惰性查找,所以在當在print之前,ORM不會真正的去進行資料庫的訪問,而是當要使用之時(EX:print)時,他才會進行訪問,而這也導致在循環中會不停的訪問資料庫,造成延遲 - 優化方式: - select_related: - 使用時機: - 在模型欄位並不複雜且數量並不多的情況下。 - 正向一對多、一對一。 - 代碼: ```python book_list = models.Books.objects.all().select_related('publish', ) # 能合併多張表 for book in book_list: print(book.publish.name) ``` - 原因: 相當於在求book_list時,就進行了資料庫的inner join操作,所以之後循環時才不用在再次訪問 - 缺點: 一次聯表查詢獲取所有的數據(一次查多張表),聯太多表時會有性能的損耗 - prefetch_related: - 使用時機: - 在查詢集中的對象欄位較多較複雜,且查詢集較大的時候 - 反向一對多、多對多關係 - 代碼: ```python book_list = models.Books.objects.all().prefetch_related('publish', ) # 能合併多張表 for book in book_list: print(book.publish.name) ``` - 原因: 相當於在Python層面上的進行join,因此該操作允許多對多關係以及反向關係,而這是select_related無法做到的。 ### SQLAlchemy和Django ORM比較: - SQLAlchemy可獨立使用,任何使用Python的專案都可以使用 - SQLAlchemy多提供了非常豐富的特性:連線池、auto-map等 - 連線池:負責分配,管理資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是重新建立一個 - Django ORM可以為你的表自動創建主鍵,而SQLAlchemy不會這麼做 - Django ORM較為容易上手 - SQLAlchemy使用了數據映射器的實現,數據庫結構和對象結構之間是分離的(要透過Session來進行交互),不像Django ORM中每一行記錄都直接映射到代碼中的一個對象,較容易理解 - 總結: - 在較為不複雜的CRUD的情況下推薦使用Django ORM - 需要使用更複雜的查詢時在使用SQLAlchemy ## Django ### Web開發: - Web服務端程序分為: - 伺服器程序(Web Server): 負責把客戶端請求接收、整理 - Web應用程式(Web Application): 負責具體的邏輯處理,也就是我們通過Django等框架寫出的程序 - 應用程式和伺服器程序兩者要互相配合,才能為用戶提供服務,要互相配合就需要一個標準來規範 - WSGI(web伺服器網關接口): - 簡介: - 本身是一個規範,是用於Web Application(應用程式)與Web Server(伺服器程序)之間的約定 - 它規定了雙方各自需要實現什麼接口,提供什麼功能,以便二者能夠配合使用 - WSGI伺服器: - 它是一個實現了WSGI協議的伺服器(server)程序,通常常聽到的有uwsgi和gunicorn - Python也內置了一個WSGI伺服器,這個模塊叫wsgiref,效率並不好,僅供開發使用 - WSGI網頁框架: - 它是一個實現了WSGI協議的web框架,可以用它來簡易的編寫Web應用程式,EX:Django、Flask和Torando等 - 其實一個Web應用程式,簡單的說就是寫一個WSGI的處理函數,針對每個HTTP請求進行響應 ### Django中間件: - 在django中,每一中間件其實就是一個類,在request到來和結束後,django會在合適的時機執行中間件中相應的方法 ### Django生命週期: - 瀏覽器 -> wsgi --process_request-> 路由系統 --process_views-> 視圖函數(和ORM、Template處理完後)--process_response-> 瀏覽器 - wsgi(web server gateway interface):web伺服器網關街口,是web伺服器和web應用之間的一種規範。 - wsgiref:是Django默認實現wsgi協議的一個模塊。 - uwsgi:也是實現wsgi協議的一個模塊,速度比wsgiref快很多。 ### 跨站請求偽造(Cross-site request forgery): - 也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF。 - 是一種讓用戶在不知情的情況下,在當前已登入的Web應用程式上執行非本意的操作的攻擊方法。 - 攻擊細節: - 簡單地說,是攻擊者通過一些技術手段欺騙用戶的瀏覽器去存取一個自己曾經認證過的網站並執行一些操作(EX:發郵件、轉帳和購買商品。) - 由於瀏覽器曾經認證過,所以被存取的網站會認為是真正的用戶操作而去執行,利用web中用戶身分驗證的漏洞,簡單的身分驗證只能保證請求發自某個用戶的瀏覽器,卻不能保證請求本身是用戶自願發出的。 - 防範方法: - 檢查Referer欄位: - HTTP頭中有一個Referer欄位,這個欄位用以標明請求來源於哪個位址。 - 在處理敏感資料請求時,通常來說,Referer欄位應和請求的位址位於同一域名下。 - 以銀行操作為例,Referer欄位位址通常應該是轉帳按鈕所在的網頁位址,應該也位於www.examplebank.com之下。 而如果是攻擊傳來的請求,Referer欄位不會位於www.examplebank.com之下,這時候伺服器就能識別出惡意的存取。 缺陷: - 有存在攻擊者攻擊某些瀏覽器,篡改其Referer欄位的可能。 - 若有真正的使用者,他們在設定時屏蔽了Referer欄位,那將造成他們無法進行操作。 - 添加校驗token: - 由於CSRF的本質在於攻擊者欺騙用戶去存取自己設定的位址,所以如果要求在存取敏感資料請求時, 要求用戶瀏覽器提供不儲存在cookie中,並且攻擊者無法偽造的資料作為校驗,那麼攻擊者就無法再執行CSRF攻擊。 - 這種資料通常是表單中的一個資料項。 - 伺服器將其生成並附加在表單中,其內容是一個偽亂數,當客戶端通過表單提交請求時,這個偽亂數也一並提交上去以供校驗, 正常的存取時,客戶端瀏覽器能夠正確得到並傳回這個偽亂數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽亂數的值, 伺服器端就會因為校驗token的值為空或者錯誤,拒絕這個可疑請求。 ### Cookie 和 Session: - 用途:皆是為了要解決網站不能保存狀態的問題。 - 比較: - 存儲位置: - Cookie:瀏覽者電腦中。【若以明碼的方式儲存,會很危險,例如:帳號密碼。】 - Session:伺服器端暫存檔中。【安全的考量下會選用 Session ,因較不易遭人利用。】 - 所存儲的資料: - Cookie:儲存在瀏覽者電腦中的小檔案,可以保持一段較長的時間,搭配程式的應用可避免重複輸入資料的麻煩,例如:登入會員。 - Session:將使用者資訊儲存在伺服器端暫存檔中,當瀏覽者進入網站伺服器瀏覽時,即會開始記錄使用者所賦予的資訊,直到到期或刪除。 - 使用者關閉: - Cookie:瀏覽器可以設定關掉 Cookie 的功能。 - Session:因為存於伺服器端,所以即使用戶端關閉 Cookie 的使用, Session仍然可以正常運作。 - 運作方式: - Cookie:將狀態資料記錄在用戶端,當開啟網站時,即可在程式的設定下將指定的資料儲存在用戶端中,並可設定該資訊的有效時間。 - Session: - 當使用者使用瀏覽器連線到伺服器時,伺服器會自動派發 SessionID 給這次的連線動作。 - 伺服器會依據 SessionID 分辨使用者來處理儲存的狀態。(默認會將 SessionID 加密處理後以 Cookie 的方式儲存在用戶端) ### MTV架構: - Models(模型): - 功能:為一個抽象層,用來構建和操作數據庫。 - 內容:包含儲存數據的欄位和行為,通常每個模型對應資料庫中的一張表。 - 對比:與 MVC 架構的 Models 對應。 - Template(模板): - 功能:與視圖做溝通,並呈現模板給使用者。 - 內容:模板包含所需 HTML 輸出的靜態部分,以及一些特殊的語法,描述如何將動態內容插入。 - 對比:與 MVC 架構的 Views 對應。 - Views(視圖): - 功能:用於封裝負責處理用戶請求及返迴響應的邏輯。視圖可以看作是前端與資料庫的中間人,他會將前端想要的數據從資料庫中讀出來給前端。 - 內容:控制與業務邏輯語句。 - 對比:(Views + Urls) 與 MVC 架構的 Controller 對應。 ### 跨域資源共用(Cross-Origin Resource Sharing)(CORS): - 介紹: 簡單來說就是因為瀏覽器的一些安全考量,你在載入其他網域的資源時會受到一些限制,解決方法就是在 Server 那邊加上一些 response header。 - 在Django中解決: 使用'corsheaders.middleware.CorsMiddleware'中間件。 ### 對restful api的認識: - 其實它本質上是一個規範,讓我們寫API時,可以更好的去做區分,也能讓前後端工程師彼此更好的溝通。 - 它通常會規範URL的形式、傳輸或表現的數據形式(json)等、CRUD操作對應著GET,POST,PUT,DELETE還有狀態碼涵義等 - 它本身是無狀態的,所以從 Client 到 Server 的所有請求,都要包含『 用於理解此請求 』的相關信息(EX:token、身份認證之類的),因為是無狀態的關係,所以當伺服器一崩潰了也能無損地轉到伺服器二(因為她要帶的相關信息都在請求中,不須再透過Session)。 https://www.cnblogs.com/wupeiqi/articles/7805382.html ### 狀態碼有哪些? - 1xx (Informational) — 資訊 - 2xx (Successful) — 成功 - 200 OK - [GET]:請求成功。 - 201 CREATED - [POST/PUT/PATCH]:請求已經滿足,且建立或更新了資源。 - 202 Accepted - [*]:伺服器已經接受請求,但尚未處理完成(異步任務)。 - 204 NO CONTENT - [DELETE]:請求已經成功,且沒有需要回應的內容。 - 3xx (Redirection) — 重定向 - 301 Moved Permanently - [*] 目標已被分配到一個新的URI,將來任何對該資源的引用都應使用此URI。 - 4xx (Client Error) — 客戶端的錯誤 - 400 INVALID REQUEST - [POST/PUT/ PATCH]:請求被認定有誤,服務器沒有進行新建或修改數據的操作。 - 401 Unauthorized - [*]:請求未被採用,因其缺少對目標資源的有效驗證憑證。 - 403 Forbidden - [*]:表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的。 - 404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄。 - 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。 - 410 Gone - [GET]:用戶請求的資源被永久刪除,且不會再得到的。 - 422 Unprocesable entity - [POST/PUT/ PATCH]:當創建一個對象時,發生一個驗證錯誤。 - 5xx (Server Error) — 伺服端的錯誤 - 500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功。 ### Http(超文本傳輸協定): - 是一種用來傳輸超媒體文件(像是HTML文件)的協定,被設計來讓瀏覽器和伺服器進行溝通 - 內容規範了客戶端請求與伺服器回應的標準,通常使用 TCP 作為資料的傳輸方式 - 請求方法(8種): - GET: 向指定的資源發出「顯示」請求,通常GET方法應該只用在查詢讀取資料 - POST: 向指定資源提交資料,請求伺服器進行處理,而資料放在請求體中 - PUT: 向指定資源位置上傳其最新內容(覆蓋資源) - PATCH: 用於將局部修改應用到資源(一般常見定義上的修改) - DELETE: 請求伺服器刪除Request-URI所標識的資源 - 不常用的: TRACE(用於測試或診斷)、HEAD(向伺服器發出指定資源的請求)、CONNECT ### GET和POST比較: - GET資料傳遞方式是將參數以key/value的方式,透過URL帶至Server端; POST資料傳遞方式是將參數放至請求體中,因此不會在URL看到參數,較為隱密 - POST的安全性要比GET的安全性高,因為GET傳遞的參數會在URL上顯示 - GET傳遞的參數會被儲存在瀏覽器的歷史紀錄中;POST則不會 - GET只允許傳輸ASCII的資料;POST則不限 - GET參數長度會受到瀏覽器的限制;POST則不會 ### POST和PUT比較: - 兩者其實都可以用來新增資源,但PUT會比較像是覆蓋或替代資源 - PUT會指定要覆蓋掉哪個資源,POST則不用 - 如果假設資料庫不能有重複資料的話,用POST新增多個可能會報錯,但PUT不會,因為它只是不停的對某個資源進行覆蓋而已 ### TCP(傳輸控制協定): - 是一種可靠的網路通訊協定,所以為了保證不發生丟包,會給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。 - 連線機制(三手交握): A發起連線請求、B返回連線確認、A發送連線成功信息 - 內容傳輸: - 確認封包機制: 接收端接收到包時要回傳確認信息給發送端 - 逾時與重送: 若接收端一直無返回確認信息,發送端則會重發一次 - 斷開機制(四次揮手): A發送斷開請求、B返回確認信息,等待B也處理完後,B也發送斷開請求、A返回確認信息 ### UDP: - 是一種非可靠的網路通訊協定,因為沒有確認機制,所以開銷較低,速度較快,通常用來做一些語音、影像的傳遞。 ## 其他觀念 ### 瀑布和敏捷式開發: - 瀑布式(Waterfall):按順序排列,因此如果上一步成功完成,項目開發團隊只會進入下一階段的開發或測試。 - 開發流程:產品需求定義 → 設計 → 開發 → 整合和測試 → 維護 - 敏捷式(Agile):是一種應對快速變化需求的一種開發模式,開發和測試是併發的,在過程中客戶、開發人員等會不斷進行溝通和調整。 - 優點: - 客戶能較早看到產品的雛形。 - 客戶能在過程中和開發人員進行溝通,獲得較符合期待的產品。 - 缺點: - 由於敏捷開發頻繁跌代更新項目,因此為了要在規定的時間內完成項目, 並隨著客戶需求的改變目標,可能會增加了項目預估的成本(人力、時間、金錢)。 ### 何謂自動化測試: - 目的:自動化測試就是把以人為驅動的測試行為轉化為機器自動執行的一種過程。 - 使用時機:所有的開銷,都是有成本的,如果編寫和維護自動化程序的成本不高,那我們就能採用自動化測試。 - 使用場合: - 普通手工測試做得到的: - 界面的普通操作 - 重複的普通測試 - 手工測試無法實施: - 大量的數據的輸入 - 大量的步驟的操作 - 系統模塊間接口的調用測試 - 工具: - SELENIUM:本身不是測試工具,只是模擬瀏覽器操作的工具,它主要是用於Web應用程序的自動化測試。 - Pytest:是python的一種單元測試框架。 ### 測試分類: - 黑盒測試(功能測試):不知道其中的業務邏輯,只知道測試結果。 - 白盒測試:了解其中的業務邏輯,並驗證結果。 - 冒煙測試:主功能、主路徑測試。 - 自動化測試:人工測試交給機器執行。 - 適用場景:軟件需求變更少、項目周期長、穩定性強的產品。 - 性能測試:模擬各項峰值和負載去測試各項性能。(一般都是對接口進行測試) ### 後端工程師目標: - 能夠處理大量資料 - 低延遲回覆速度 - 資料安全性 ### Line Bot基本流程: - Line Client:就是使用者使用的終端介面,通常是 Line Channel - Line Server:是接收 Line Client 的互動請求 - Webhook Server:是我們編寫的商業邏輯、回傳 Component 規劃以及 Line Bot SDK 運作的地方 - 流程: - Line Client -傳訊息-> Line Server --> Webhook Server(會先判斷是不是從Line Server來的,是的話會繼續執行) -返回結果-> Line Server --> Line Client ### Git原理: - HASH(哈希、雜湊)算法: - 分為Hash Function(雜湊函數)和Hash Table(雜湊表) - 雜湊函數: - 是一種將輸入值映射到另一個值域的技術。 - 不管多長的明文透過雜湊函數後,得出的密文長度皆一致。 - 這種轉換有一個很重要的特性就是「單向」。(不可藉由HASH輸出值推導回原值) - 雜湊表: - 儲存(Key,Value)這種對應關係的資料結構。 - key為原始輸入,value為經過雜湊函數的輸出值。 - 衝突(Collision): 當不同的原始輸入,經過雜湊函數後,卻得到相同輸出值,這時就會產生衝突。 - Git底層的雜湊函數是採用SHA-1。 - 保持資料完整性: - 先將原始文件經過SHA-1,轉為一個密文。 - 網路傳輸(上傳或下載等) - 把上傳的資料經過SHA-1轉為另一個密文,兩個密文互相比較,有不同則表示數據有丟失。 - 保存版本機制: - 快照: - 快照並不是整個項目文件夾的副本,快照僅僅是一個記錄文件結構的文檔。 - 就像是版本資訊對象,每個對象都會有一個編號,透過這個編號我們可以進行git reset等操作。 - 物件: - 用來保存版本庫中所有檔案與版本紀錄。 - 物件是一個「特別的檔案」,將檔案的內容中取出,透過內容產生一組SHA1雜湊值,然後依照這個SHA1雜湊值命名的一個檔案。 - 物件又分為「目錄資訊」與「檔案內容」,我們稱為 tree 物件與 blob 物件: blob 物件:就是SHA1雜湊值為名稱的檔案。 tree 物件:儲存特定資料夾下包含哪些檔案,以及該檔案對應的 blob 物件的檔名為何。(簡單的說就是資料夾的概念) - 每一個快照(版本對象)中可以包含多個tree和blob物件。 - 索引: - 則是用來保存當下要進版本庫之前的目錄狀態。 - 「索引」是一個經常異動的暫存檔,這個檔案通常位於 .git目錄下的一位名為 index 的檔案。 - 用來紀錄有哪些檔案即將要被提交到下一個 commit 版本中。 - 索引流程: 1. 要使用 Git 版本控管,必須透過git init先建立「版本庫」。 2. 在「工作目錄區」進行開發(建立目錄、建立檔案、修改檔案、刪除檔案等操作)。 3. git add, git mv等操作會將「物件」的索引從工作區添加到暫存區(或是索引區)裡。 4. git status依據「索引」當下的狀態,顯示哪些變更的檔案在暫存區或工作區裡。 5. git commit 會提交變更,把版本資訊寫入到「版本庫」當中,並把分支指針指向此快照(版本對象)。 - 管理分支機制: - 每個分支都是一個「指針」(包含master等),他會指向版本對象。 - 創建一個分支,只是相當於新建了一個指針,並指向一個版本對象,而並非是創造所有文件的副本。 - HEAD是一個特殊的指針,他是會指向當前使用的分支,這樣就能控制哪個分支要進行修改。 ### git基礎(詳細在git筆記): [![hackmd-github-sync-badge](https://hackmd.io/EQdno6aHSdSrCOnFk2IGwg/badge)](https://hackmd.io/EQdno6aHSdSrCOnFk2IGwg) - Git可以分為 Local(本地)和 Remote(遠端)兩個環境。 - Local: 分為working directory(工作資料夾)、staging area(暫存區)和 repositories(倉庫) - 在自己開發時: - 上傳:工作資料夾 --add--> 暫存區 --commit--> 本地倉庫 --push--> 遠端倉庫 - 下載更新:git pull <遠程主機名> <遠程分支名>:<本地分支名> - 等同於 git fetch(抓取遠端的branch) + git merge(將遠端branch和本地branch合併) ###### tags `面試`