發表文章

[工作日誌] #9 整合測試系統

開發時期的整合測試 請認真想想,如果製作一個拿來驗證開發成果的整合測試系統,與上篇提到的自動化整合測試與驗證系統,他們的差別在哪裡? 後者其實就是前者的延續,甚至開發者製作了測試開發用的整合系統,後續的自動化驗證系統,也可交由非原開發者去製做。 前者應該已經要把有什麼對象,有什麼流程,有什麼料都寫好了。 後者只要拿來應用,組裝,加上一些驗證的程序即可。 但無論無何,這個部分一定要是原開發者製作,因為他最懂,因為他是作者,細節怎麼搞?為什麼那樣搞? 考量是原作者考量出的方案,當然要怎麼驗證要他去想。 不然維運人員何其無辜,就真的不懂呀。 我們的不足 這部分獲得開發者的保證,開發與維護應該就可以切開了。 當然非常可能有漏考慮的部分,有時候還是得回過來靠原開發者補足,一定還是有開發與維護人員一起討論的情況。 其實也是我們部門沒有自動化測試人員。 我知道外面有的是把這類的人員,有的是編在開發人員上,有的是算再維運人員身上,但我們就是沒有。 送測部門,只能做人為操作測試,呵呵呵.......... 當然模擬使用者操作也是非常非常重要,送測部門也很熟練怎麼去擬訂人為操作的案例或SOP。 但有些東西,尤其是扯到大資料,大量處理,沒有自動化測試,沒有環境沒有條件,沒有拼死都要做mock銜接現實環境的限制然後作整合測試。 令人非常擔心,好幾萬的資料,好幾萬的request同時過來會不會錯,人工是無法測的。 上線 = 另一種送測,有爆掉的可能,多少心理可以有所準備。 當然自己上線前有時間就人工的code review,工作時間外常常也在思考會不會哪邊有意外,用自己本機有限的條件做片面或有限的測試等,努力了,也是非常不希望上線出問題。 這樣也好累,沒有令人心安的保證。 人類有人類的優點,機器有機器的,互相難取代。 所以,事發後......公司方面的反應,有的沒心理準備的感覺,在下面的我也是覺得非常無言。 要馬兒好,要又馬兒不吃草。

[工作日誌] #8 自動化整合測試與驗證系統,全面掌握問題的希望

自動化快速驗證系統 - 中央集成 不論是誰來反應問題,維運人員收到問題回報或者詢問,一定想要用最快的速度確認到問題原因,或者是不是真有問題還是誤會一場。 確認追求越快越好,問題處理完善追求越快越好,速度代表的是績效,是專業,是品牌,是價值。 問題一: 公司想不想追求這一點,部門想不想追求這一點,是的話,願意付出多少代價? 沒做好心理準備,沒願意犧牲、付出成本,一切都是空談。 什麼狀況都一樣,只願意給香蕉,只能請到猴子,猴子的作業,應該要有心裡預期可能會面對到時遇到什麼不良結果。 問題二: 該怎麼做? 製作自動化整合測試系統,而且是自己客製化的驗證系統。 是系統,不是單一工具。是整合驗證與測試,不是單元測試。 先分析現況和確認情報。 1. 面對有問題的資料,我們不敢輕舉妄動。 這很好理解吧?你很想把它的資料丟到程式重跑一遍,看看發生什麼事? 但是你敢嗎?後果可能錢會亂給,或者亂扣,或者寫入錯誤資料,寫入資料的地方說不定還有可能是別的部門的, 客人可能覺得你亂動它的資料,到頭來就會面臨四面八方的怒火。 更何況你怎麼快速的拿到有問題的相關資料? 即便你有能力把它丟進系統重跑,但就能知道它在系統每個環節的作為,有如你的預期嗎? 所以需要什麼淺而易見了吧。 1-1. 自動取得關鍵資料。譬如說輸入了使用者ID,程式自動挖出這個系統業務相關的參數給你。 1-2. 不要真的寫進資料到系統。該寫的沒寫,問題點好找,但若是中間的計算或處理有問題該怎麼判斷? 如果真的為了重新執行一遍,把資料寫進去了,你不是完蛋? 客人下單買了一件貨,被你查問題重跑兩次,它不就買了3件?但客人的問題是付款了系統確說沒收到。 所以驗證程式要自動避開真的寫資料的部分,中間需要假的資料作串接,拼死也要弄個假的出來,讓整個流程可以完整跑過,確認問題狀況。 1-3. 透明觀察箱。別於存在記憶體的程式,看不見在幹嘛,別於可憐巴巴地找程式每個階段,有沒有錯誤或異常的log。 這個系統要主動回報每個關鍵步驟,關鍵單元的執行結果或狀況, 好比我的專案,系統作業完整流程,DB有5個操作,redis有4個讀取,3個寫入, 有抓取七個部門的API來源,系統中間有6種關鍵計算處理, 每個部分都要回報,取到的資料是什麼,寫入有沒有

[工作日誌] #7 大膽假設,小心求證

以下都是很主觀的個人經驗 大約在退伍後,剛進入職場當做工程師一年左右,被指派主持開發一個蠻重要的案子。 有次被調列的問題有點多,老大忍不住有點火大地過來,要來對每個問題。 那時候我也情緒不是很好,有事先稍微看一下清單內容,於是當場我跟老大的解釋是對方又雞蛋裡挑骨頭。 老大不爽的問我說,你真的都看過了嗎,每個都有去理解嗎? 就算上次對方雞蛋裡挑骨頭好了,這次呢?真的是這樣嗎?你有好好去看了問題嗎? 我稍微愣住,但是還是回答有看過。 老大又問我是怎麼看的,方法是怎麼做? 於是我們當場挑了幾個問題,重新看過,跑一次怎麼分析問題和做處理。 一輪下來,我記得有兩三個問題真的是誤解了,問題雖然跟之前的很像,但原因是不一樣。 有個問題上次是真的挑骨頭,這次卻是真的有部分我們沒處理好。 老大留下一句話,「假設完了,就好好求證,求證後再說出來」,後續就交給我。 這事件是讓我非常非常印象,意識到我真的做錯事情,我的過往經驗和莫名的自信,害了該有的處置。 人無完人,莫名自信爆棚而幹的錯事,也還是在發生。 但想到就提醒自己一下,可以的話,就停下來多想一下,多求證一下。 工作上事情交給你,徵詢你的意見,是願意相信你,別辜負了。 後來換了工作,碰到的人比較多了,發現竟然有的人不會放下矜持做假設,不敢假設, 人家說什麼他聽什麼,跟他問什麼講不出什麼意見來,那也沒關係。 所以後來,能夠提出假設的人,在我心目中都給予至少某種程度上的肯定, 能夠試著去設想問題,已經是不簡單的事情。 但更多人止步於此吧。 要求證到什麼地步,要推論到哪個層面和範圍,的確真的很看個人的經驗,和自由心證。 我看到的是很多人已經很習慣的嘗試假設問題,卻疏於去求證,放棄邏輯推理的練習。 握有什麼的情報和證據,可以做到什麼地步的結論和推理,這是一直需要練習的, 這是人類的心理活動,而非如程式有固定公式,有什麼input就可預期有什麼output, 有時候也不是若P則Q,或非P則非Q這麼簡單,首先你要知道你的P和Q有沒有抓對是吧? 有時候沒痛過也學不得教訓吧? 若以前我沒那種經驗,也許我與很多人也沒什麼不同,掛著專業的頭銜,夸夸其談,實質內容卻可能有些問題。 大膽求證,能假設多廣就多廣,我是做系統的,但小心求證!

[工作日誌] #6 技術債,迫切開發,實驗

說明 有些問題的類型歸類,實在難以釐清。 可以比較確定的方向是大概就兩點 1. 這問題責任是算在開發部門 2. 基本上,我要講的內容,這也算是極端問題的ㄧ種分支 如果開發階段或者測試階段就很常發生,又無法解決問題,我相信大家也不會用。 案例 系統流程大約是這樣 1.php收到request --> 2. php 將資料A寫入redis,hset --> 3. php 將資料B寫入redis,rpush --> 4. golang 將資料B讀出redis,lpop --> 5. golang 將資料A讀取redis,hget 結果在運行每個月上千萬筆以上的作業,據我聽到的傳言平均每個月會有一兩筆有問題。 一個A理論上對應一個B,有問題的是有時候會發生只有1個B卻有2個A,或者1個B卻沒有A的狀況。 1 ~ 5 步驟到底哪裡有鬼,我也不知道個所以然,也沒有切確方向。 但問題範圍在1~3的部分比較有可能,因為golang 做lpop和rpush在系統其他方面的資料處理量也很可觀,還沒有聽過有問題。 所以我判斷應該是php 那邊做rpush有問題吧,fuel php 的framework也確實好幾年沒更新了。 在那個php專案裡面也從沒寫過rpush的操作。 事至如此,我覺得我也有錯,因為當下接到問題處理的人不是我,我就提出我的意見後,繼續去做我的事情了。 算不算親手製造一個悲劇?該死的風氣 然後後續就有點債留子孫的感覺 問題發生原因是什麼,發生的機率又低的很可怕,以目前資源和環境你想重現,又沒辦法。 後來問題重複出現,半年過去,出現過幾次,以這麼大量的分母,這個分子根本九牛一毛。 為什麼會容許重複出現呢? 我想是實在問題出現機率太低了,我們有更重要的東西要優先處理,又或者所做的修正是頭痛醫頭,腳痛醫腳,所以當然弄不好。 這點我也沒辦法,當我不知道問題切確問題點,也許給出的分析或處理方案也是頭痛醫頭,腳痛醫腳,這是沒有辦法的事情。 優先處理已安排好的專案需求,優先處理被客訴的問題,優先處理明確明顯的問題。 對這是我們的現實沒錯,但探究困難問題的原因,我認為不該被推到第四象限,不緊急不重要的部分,然後改天就被默默遺忘了。 好像只是要個交

[工作日誌] #5 若問題類型是極端狀況,那是寶藏

極端狀況的認知 有時候狀況不可預期,無法預期就無法評估或控制。 極端狀況所造成的災難,很明顯與直接地造成公司或部門的損失。 災難範圍多有大,取決於看運氣,可能引發ㄧ點點小部分的錯誤或異常。 有可能引起一連串的反應,拉著一卡車的相關部份一起陪葬。 兩者我們都有遇過。 我所謂的極端狀況,指的是,超出系統架構設計上能承受的負荷。 系統設計和安排上,總有些前提,和預期的控制範圍,若失控崩潰絕對不會有好下場的。 危機、轉機,發現價值 這些處理和理解極端狀況的部分,撇開公司的受損另外討論,對技術單位根本是寶藏。 技術單位的技術儲藏、看家本領的技術底蘊,不是從這裡來,要不從哪來? 自己的架構、設計、環境、業務處理邏輯,從外面哪能遇到的這麼貼切的類似情境, 外面哪裡有可參考的極端狀況,成因和處理可以學習? 這種成因,分析方式,試驗手法,以後要避開的設計誤區,考量狀況重點,最應該寫成文件或範例,並且在部門交流內讓每位開發者深刻認識與學習。 不然災難過後所留下的ㄧ點好處,只有能夠理解的人獲得殘餘價值,然後在其他人面前大剌剌的漂過,然後呢? 我的媽呀,同一個部門大家做的業務性質處理很相近,其他人改天再弄一次嗎? 付出群體的代價,卻沒有群體的收益,倘若技術只綁在少數人,如果人走了呢?技術部門是不是某種程度上又打回原型。 比喻 接下來我就舉兩個例子,引發災難ㄧ小一大,兩份珍貴的收藏。 剛好都是與資料庫相關的case。 看不懂的人可能覺得沒價值,跟一般的小錯誤沒什麼兩樣,但是請聽我說來,這跟一般的小錯誤有什麼不同。 很多的小錯誤,業務或邏輯,或者粗心所製造的錯誤,有些方法可以防範,邏輯思考模式經過長期訓練,也可以趨於完善,可以檢討SOP,或用測試手法預防。 但這樣能解決的問題,還叫做遇到極端狀況嗎? 想得到,測得到,預防的到就不叫極端狀況了,所以這種經驗你說可不可貴。 遇過了,之後可能就不一樣。 打個比方,你要防衛敵對國家的武力進犯,你的評估是對方武裝實力其實跟我們差不多‧ 你做了海上防禦部屬,陸上陣地部屬,空中預警部屬,甚至綜合打擊部屬,因為我們要打人家也差不多是這樣的方向。 結果開戰當下,敵人竟然使用太空打擊武器! 如果僥倖活下來不死,是不是應該警惕地審慎思考過所有環節?首先

[工作日誌] #4 專案規模的成長路

小系統,大系統 如果專案本身規模小,或處理量小,在程式架構設計沒有重大瑕庛的情況,測試程序完成上線後, 要遇到的問題或收到bug回報的機會本身就比較小,往往feedback的問題也比較無關痛癢,或者不會到需要系統功能掛維護,或者整個系統crash。 大規模的系統往往無法單憑人工檢查,就可以得知受災範圍,或者做資料修正,ㄧ旦有事,往往大事。 小規模系統出事的處理經驗,很難套用於大規模專案的處理。 越大的系統處理成本越高,應該是可以預期的,觀念上應該做好有這樣的心理準備。 各方面影響也都不同,沒人敢說成本可以控制成線性成長。 處理10萬資料的系統,要花10萬塊成本的話,有人敢說處理100萬資料的系統,只要花100萬嗎?不一定,很難講。 自然而然的事情 如果以一樣的設計基準點,每個小時處理上百個資料的業務計算,和每個小時處理上萬個資料業務計算,誰比較有可能出狀況不用明說。 拿個現實上的比喻。 為什麼現代人比起古代,更多的人口比例得癌症。 文明病是真的文明病,主要原因還是人類平均壽命拉長,活得越久本來就越有得癌症的風險。 細胞分裂越多次,身體機能越老化,分裂發生錯誤的機會當然跟著提高。 有些人成天依據自己的意見,或者次因怪東怪西,不如看看20歲以下的人口得到癌症的比例是多少。 看待事情若無法得知原理,起碼要相信真實的數據。 修問題如治病,先了解病因和病況,確認原因後再治療。 若是生大病,怎麼可能用小病的治療方式,讓身體恢復健康。 頭痛醫頭,腳痛醫腳,是無法治療內分泌失調。 遇到嚴重的新問題,會頭痛的困難點有兩個 1. 如何判斷是大病? 大概有些特徵,譬如說過去經驗無得參考,成因複雜難以簡單分析出來,規模大才會發生的問題,極端狀況才會遇到的問題。 正向思考一下,對目前來講都是大病,當我們夠經驗了,經歷過了,在未來就是小病,也意味著我們可以作規模更大更精密的系統了。 假設某個設計方式可能存在缺陷,系統經過那個部分,發生錯誤的機率是萬分之ㄧ,系統規模小,每天只執行10次,運氣好可能好幾年都沒發現那個地方有缺陷。 承上,假設系統使用的頻率變高了,每天執行1000次,可能一個月就遇到了問題發生,能解決就是經驗,下次設計時避免掉,這個問題對我們來說就不是什麼大事,已

[工作日誌] #3 我們的開發與維運人員

變形的作業方式 開發人員不做開發文件,卻投入製作某種意義上的維運文件。 沒錯,有些know how開發者才知道,但維運者不知道就無法判斷問題或處理嗎? 已經驗證過的input和output真的有需要懂理面在做什麼? 如果如此,那麼這個模式背後指出許多問題。 1. 開發與維護根本沒實質切開,仿佛高偶合的程式碼,切離開發那塊knowledge,是做不到的。 2. input和output無法控制範圍,無法信任系統會處理到什麼狀況,產出什麼結果。 3. 開發人員無法給維護人員保證,維護人員總需要開發人員協助。 分析 所以開發人員的產出結果能夠被保證,input和output範圍能夠控制,維運人員可以在有限的範圍搜索問題與釐清feedback。 能做到如此,我們就可以破除困境。 開發人員: 是大廚,食材原料是什麼,中間加了什麼調味料,做法工藝是什麼,煮出的東西大概會怎麼樣,雖然味道最終是客人品嘗。 但做菜的前後,當然是主事者最清楚,維護的人怎麼可能知道,所以有需要這方面的說明和了解當然找開發者。 開發者握有這部分的大權,訊息、情報最完整的資訊,call 什麼資料庫,call什麼API,資料怎麼加工,過過什麼驗證檢查,就開發者最清楚。 文件無法真實代表程式怎麼跑,這部分的knowledge又會隨著時間流逝,ㄧ點一滴的從開發者的腦袋中流逝。 開發者應該即時的花費精力付出這部分,但要怎麼做? 維運人員: 是場控,是經理,是服務生,反正做菜以外全包了。 要做的事情大多是接收客人反應,確認狀況,假設客人抱怨點了牛排七分熟,卻拿到豬排還不熟,就開始找問題了。 首先確認客人真的是點牛排七分熟,再來確認點餐的訊息有傳到內場,內場真的是收到牛排七分熟的點餐。 假設這個廚房非常先進,收到點餐,有特殊機器自動抓把肉抓出來處理烹煮,烹煮之後自動傳到人員裝飾擺盤,就送到外場。 所以維護人員再找,是不是牛肉櫃裡面有人放了豬肉進去?烹肉的機器是不是故障?傳遞到擺盤人員的中間過程是不是有問題? 送餐的人員是不是送錯,客人是不是真的拿到豬排還不熟? 他不應該懷疑機器收到抓牛肉的指令,卻去抓了豬肉。 他不應該懷疑,擺盤人員故意惡搞。 這些應該是要被驗證和保證的部分。 可是今天如果內場他完全進不去,

[工作日誌] #2 談談撰寫文件

結論 文件能不能解決問題? 某些目的和用途上能提供的幫助非常有限,在我全程主持的幾個專案,努力要求了,了解了某些事情,最終釋懷了些一直堅持的想法。 放下別人的要求,繼續堅持認為該做的事務。 以文件為主軸,在部門的環境內這個方法行不通,因為我們頭痛的問題與面臨的狀況,文件並沒有太有效與即時的助益。 文件在開發上的好 開發的過程中,文件可以很有邏輯條列規格,多人開發、前後端溝通上大幅地減少溝通落差,這點非常有幫助。 在文件幾乎齊備的情況下,就不太會發生以下情形 1. 多人開發上互相介接,介接上有嚴重錯誤或誤會。 2. 進乎成品後才發現團隊有功能漏做,以為有人會實現缺少的部分。 3. 需求不明確,送測或上線後才發現。 4. 上線後發現系統不穩定,因為未在設計階段做考量,後續難以補救。 文件不能有效地解決,目前往往遇到的瓶頸問題,不過帶來的好處某方面來說,依舊難以取代。 我認為文件是製作好專案一個必要的環節,所以都會做文件,也一直嘗試做出每個專案最適合的文件。 一直以來也不斷鍛鍊自己撰寫文件,畫各種說明圖的技巧,這部分在有限的成本與考量上能做的已經趨於極致。 需求文件,SA,SE,SD,DB規格,API規格,Redis規格,專案注意事項,有限的壓力測試說明與報告,流程圖,架構圖,河道圖,有序圖,FSM,看專案用什麼表達可以最清楚關鍵重點,持續以來的自我要求,好像達到某種程度或者說是自己的極限,以2/8法則來說,要再更精進,需要再花費80%的精力才有20%進步,何必呢?文件只是一種工具。 一路走來 目前本分是工程師,做著工程師的工作,理所當然對於寫文件也難相比設計程式上的幹勁,只不過是必須的部分,對此報以敬業的態度一直在努力。 自己好像太過一廂情願的往前跑,情境好比抵達里程碑後停下腳步環顧四周,才驚覺沒人跟上(不知道是不想跟我著我的方向走,還是跟不上),除了自己的腳印只有荒煙漫草,不見他人人影。 不是我在的專案,文件不文件的,撰寫文件的推廣上,逐漸感到意興闌珊。 他們需要的不是文件。 也許大部分人很難理解文件內容描述背後的意義。 很多人未俱備契約精神,定好的規格,沒那麼嚴格考慮或遵守。 過往經驗,重視文件的起點 不知不覺,回過神來,我也沒想到現在的自己對於文件的理解上,在部門內

[工作日誌] #1 進公司三年以來心情最沉重的事件

至少我做到了用更多的耐性靜觀其變,更好的隱藏自己的情緒,在其他人面前平靜的討論與提早離開。 不光是技術,或者概念,個人社交的能力或許這樣子......也算是進步,今天不知道為什麼還能試圖表現冷靜。 #前兆 事情是這樣的 差不多這兩個月以來,我主導與設計程式架構的專案,約略可以算三個,一直接連過幾天輪流就出狀況。 不是每個問題我都知道發生的詳細原因,左鄰右舍或座位前後左右的同仁在討論時,略有耳聞而得知有這樣的事情。 距離系統上線已經好一陣子,我離開專案開發和維護有段時間,頭一個專案完成甚至距今快要有半年之久。 做處理和維護的人不是我,但若有我知道的case,多少也會關心一下,畢竟是這幾個專案的首席。 自己的孩子長得怎麼樣,有心力還是會想關心的。 接連的出狀況,終於有個引爆點讓部門整個炸掉。 主管們的反應,可以隱約得知承受莫大的壓力。 #事發 前天引爆點的事故,除了當值的上面ㄧ級主管和值班同仁,自己也身受其害。 凌晨2點被電話吵醒,3點多才睡著,4點被叫起來支援直到天亮,到現在過兩天了生理時鐘還怪怪的,較年長的ㄧ級主管和連續上陣17小時的同仁可見更不好過。 問題的源頭是提供資料的資料庫部門資料有漏,ETL出問題,當日下午兩點的排程執行下去,30萬筆資料已經進入後續流程當然有問題,寫入有問題的資料。 資料庫部門修正了第一次還是有問題,重跑了資料,值班的同仁用工程師的方式修正資料,重跑排程,晚上又被客訴,再次確認是資料庫部門修正有問題。 他們再次重新修正資料,又重跑排程,又有不知名問題,所以臨時拉我支援。 後來證實這不明的問題,是因為設計上的限制所導致,(當時應客戶做奇怪的需求設計),這種排程重跑遇到撞到那種設計考量,當然會出問題。 (詳細業務內容不方便說明) 這個重跑工具最初設計是為了發生事故沒按時啟動,過了時間點可手動啟動,而不是跑過有問題再重跑而製作的‧ 之前因應某些資料來源錯誤做處理,也有執行過這個工具兩三次,因為那時處理的比現在資料量少,剛好沒撞到那個設計限制,我自己也時間久了忘了這種情況。 我們需要接別的部門資料有7種來源,經過幾十道程序,做業務邏輯判斷後處理,資料庫部門提供資料有誤雖然之前也有前科,但不一定每次是他們。 總之這個事件曠日廢時的處理許久,最後又沒有一個完好的

[Go] Golang 相對路徑以及沒有使用gofmt的衍生問題

今天遇到一個奇特的問題 在我將專案內import 的相對路徑改成絕對路徑的時候,竟然出現了一些不知道從哪裡來的物件名稱。 想當然爾,編譯是不會過關的,但前人的編譯確可以順利通過。 肇事原因,就是前人的兩個做法所影響 1. 用相對路徑去import package 2. 沒有用gofmt 情境如下: "../../kernel/api" 這個其實是幫你找到一個叫做『api 』的資料夾位置 如果我在『api 』這個資料放的package 名稱叫做myservice 這樣是可以過關的,而且你在import "../../kernel/api" 的檔案內 可以用 myservice.XXXX ,這個package內的東西! (原則上package的命名和外面的資料夾名稱應該一樣,這個是不好示範) 目錄如下 kernel - api - send_request.go send_request.go 檔案內容 package myservice func begin(){ // todo function implement } 某個有使用send_request.go檔案的內容 package logic import "../../kernel/api" func buildLogic() { myservice.begin() } 我看到就是類似myservice.的東西,滿臉的問號它是從哪打來的? 會有這樣的結果,也是因為沒用gofmt 如果有用gofmt,看到未使用的 "../../kernel/api" 早就被砍掉了,因為裡面沒有地方是用api開頭。 挖屋..... 當然可以的話,還是希望大家都能用絕對路經(專案名稱開頭),和gofmt輔助格式整理。 Created Date : 2018/09/28 Last Updated Date : 2018/09/28

[Redis] [Go] Send 不加 MULTI 會怎麼樣

圖片
做redis transaction 基本上先放MULTI,再SEND要操作的行為後,最後送出EXEC。 但SEND 本身是在做queue的動作,即使沒有先送MULTI,也是可以成功把做queue的指令丟給redis。 為了弄清楚差異,做了一點實驗,以下搭配GOlang。 實驗一: 說明:         將最後的EXEC註解掉,中間插個DO。 結果:         結果DO以前有寫入redis,DO以後的沒作用。 實驗二: 說明:         根據實驗一的基礎上,但最一開始有用MULTI包起來。 結果:         結果即使中間有DO,但都沒寫入redis(DO也沒寫入?)。 實驗三: 說明:         將實驗二最下面的EXEC註解打開。 結果:         通通寫入redis。 結論:                 如果沒包MULTI,會因為有DO的指令,沒而被一起執行下去。         如果有包MULTI,因為MULTI會認EXEC,而導致中間的DO,被吃掉。         碰到EXEC,不管之前有包幾個MULTI,都會一併執行。 Created Date : 2018/08/16 Last Updated Date : 2018/08/16

[Go] Golang 的 slice 進階know how

之前聽別人分享使用slice 遇到有些坑,但未說明來由。 最近在閱讀 Golang 新手可能会踩的 50 个坑 ( 英文原文 ) 也看到關於slice說明的一些現象,為什麼有些值會無故消失,或者無故被更改,於是好奇花了些時間研究了一下。 下列說明配合source code,這邊就不重複貼了。 my source code on github 先說結論,slice的使用方式是pointer。 slice、map、channel 三者在Golang使用上是操作方式是pointer,不熟悉的話建議先把內容copy起來再操作比較保險。 請參考GO FAQ Why are maps, slices, and channels references while arrays are values? 我自己在寫FAQ的心得文章 有印象。 當下是以為在傳遞function的參數,和接受參數的部分對於 maps, slices, and channels 有這樣的說明,不過現在看來這個也是在講平常assign的使用上。 實驗分為test1() test2() test3()。 test1() 和test2() 把某個slice assign到另外一新的變數,表面上看似有了兩個slice,不過是多了一個新的變數名稱,其實指到相同的slice內容而已。 如果改了其中的內容,兩個slice都會影響到,因為他們是指向同樣的地方。 但若(舊的slice + 新的value) ----> 就會自動產生出新的slice,於是跟舊的slice沒有關係了,各改各的不會受影響。 test3() 將記憶體位置印出來,事實上實驗起來,可以發現每個slice裡面的index皆占了一個記憶體空間,假設有兩個slice,裡面的元素可以指向同樣的地方,也可以分別指到不同的地方 x := append(s, 11) // 只有擴到x,但s還是舊的 fmt.Println("cap(s) =", cap(s), "ptr(s) =", &s[0], "ptr(x) =", &x[0]) fmt.Println("cap(s)

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART4 END

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART4這裡有 Functions and Methods   Control flow Packages and Testing Implementation  Performance Changes from C --Functions and Methods-- Why do T and *T have different method sets? 接收到型態T的對象,有型態T所有的method,但如果是接收到型態*T,則會擁有型態T和型態*T的所有method。 如果interface裡面包含*T,那麼操作的行為會是pointer,如果是T,那操作的行為只能是value的處理方式。 如果是傳value,copy值之後,就跟原本被copy的部分沒關係了。 What happens with closures running as goroutines? func main() { done := make(chan bool) values := []string{"a", "b", "c"} for _, v := range values { go func() { fmt.Println(v) done <- true }() } // wait for all goroutines to complete before exiting for _ = range values { <-done } } 這個範例是在學GO蠻經典的例子,結論是永遠不要在gorutine裡面直接使用外面的變數。 因為goruntine宣告後並不是馬上建立的,可能等一下才建立,以及複數個gorutine建立起來可能沒有順序性,此時外面的變數已經不知道跑到哪裡去了。 有兩個比較直觀的解法,一個是每次都直接將變數傳入goruntine的function

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART3

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART3這裡有 Values   Writing Code   Pointers and Allocation   Concurrency --Values-- Why does Go not provide implicit numeric conversions? 要考量的問題很多,轉換後是否為正數?值會多大?會不會溢位?是否可用? 自動轉換數字型態所帶來的混亂大過好處,沒有特別設計的compile架構很難滿足這個機制。 對GO而言即使64-bit的系統,int也不等於int64的型態。 Why are maps built in? 如strings一樣重要,這種結構可以滿足廣大的定義需求。 map結構,雖然語意寫法稍微不方便了點,但complie的速度快,這應該是可被接受的合理平衡點。 Why don’t maps allow slices as keys? map 裡面的查找,需要equality 運算子(我不清楚這個equality是什麼)。 對於slice是沒有equality 運算子的,但array,和struct有,所以可以當作map的keys。(我的天呀) (會問這種問題,真是超乎想像) Why are maps, slices, and channels references while arrays are values? 為什麼map, slices, and channels 是參考,arrays 是數值。 我的理解是在講call by references 的 references,還有 call by value的value。 map, slices, and channels 是指標,所以不可能生出非指標型態的實體,GO也掙扎的想把array做成這樣。 但會有一些很複雜的作用,所以GO放棄,還是維持value的可用性較高。(這部分看得不是很懂)  -- Writing Code--   How are libraries documented? godoc 提供的功能豐富,可以滿足

[Go] Golang了解 array 和 slice 的差異,簡單說明

array 一開始就宣告大小,不可以再變動。 slice 則是動態增長。 對於array的型態來說,[2]int 和 [3]int 會是不同的型態,長度大小可以理解為某種附加型態,要有指定大小+中括號才是array。 array和slice在執行速度上也差異很多,在我macbook pro 2017,的簡單測試1到100階乘的加總,一個是nanoseconde的運算時間,一個是microsecond。 Created Date : 2018/08/07 Last Updated Date : 2018/08/07

[Go] Golang用法 function input & output 參數可以同樣型態放一起

參數太長該怎麼辦,同樣類型的可以寫在一起。 這件事情我知道的時候還蠻訝異的,同時,又得知不只傳入的參數可以這樣,return的型態也可以這樣搞。 另外,若事先指定回傳的變數名稱,可以在function當中各處先assign你要的回傳值到這些變數。 Input的參數可以類型寫一起 func GetMyData(name string, sex string, birthday string,id int, number int) { } // 可以改寫為 func GetMyData(name, sex, birthday string, id, number int) { } return的參數也可以類型寫一起,並且偷偷宣告變數名稱 func GetMyData(name, sex, birthday string, id, number int) (bool,bool){ } // 可以指定命名 func GetMyData(name, sex, birthday string, id, number int) (isOK bool, isPassed bool){ } // 當然也可以匯集 func GetMyData(name, sex, birthday string, id, number int) (isOK, isPassed bool){ } function 中串插要回傳的值 func GetMyData(name, sex, birthday string, id, number int) (bool, bool){ isOK := true isPassed := false return isOK, isPassed } // 就可以改寫為 func GetMyData(name, sex, birthday string, id, number int) (isOK, isPassed bool){ isOK = true // 中間有些co

[Go] Golang用法 package import 前面的底線

package import 前面的底線 init() 是GO 的關鍵字,每個package都存在一個這樣預設的init() 對於main package來說,在進入main()之前,會先執行init(),如果你有寫在這個package某處的話。 在import package時 對於引用package來講,只會執行這個package的init(),其他部分不會用到。 如使用gorm,我只想用mysql的部分,因此按照文件,我要import “github.com/go-sql-driver/mysql”,但前面加上_ 即可 import ( _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) Created Date : 2018/08/03 Last Updated Date : 2018/08/03

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART2

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART2這裡有   Types   Types Is Go an object-oriented language? Go 說是,也不是,有OO的風格,但沒有『繼承』,在GO裡面的interface也跟其他語言的interface有所不同。 透過interface可以達到某些類似subclass的目的,但GO聲明這樣的東西,絕對不等於subclass。 (BOX 和 UBOX 的概念我不清楚,找到的參考是 https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing ,但還是不懂意思,GO表示可以把ubox integer也塞進struct,這很厲害?) 再次聲明,沒有了『繼承』,少了負擔感覺真好。 (OS: 你到底多討厭繼承,這好像我第三次看到了,然後我也覺得就直說不是傳統物件導向的語言,別甲仙啦。) How do I get dynamic dispatch of methods? 『dynamic dispatch of methods』是一個概念,搭配Polymorphism的概念一起看,在GO能做到這件事的唯一方式就是透過interface。 在struct裡面的method和具體的method都是靜態處理。 Why is there no type inheritance? GO想走別的方向,不想要有『繼承』。 沒有『繼承』帶來實質上的好處,『繼承』機制所需要的紀錄彼此關係這件事情,造成很高的複雜度和負擔。 GO的interface可以達到你的目的,再者,沒有了『繼承』就不需要管型態與interface的『明確關係』,每個type可以乾淨的跟interface結合。 (所以其他OO語言,有繼承的type,如果有使用interface,他們之間會定義某種關係狀態,拖累某些處理和速度是嗎?) 舉例fmt.Fprintf 可以印出任何型態的東西,io.Writer可以各種寫入,就是靠『沒繼承』+ 『interface

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART1

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART1這裡有  Origins  Usage    Design --Origins-- What is the purpose of the project? 依賴管理對於現在語言非常重要,C語言有著絕佳的速度,但header file的方式在管理依賴這件事上實在非常糟糕。於是想要一個速度快,依賴管理方面又能滿足我們的語言。 沒有『繼承』的概念,這點可以省略『判斷兩個型態彼此之間的關係』所花的時間。(這點蠻有趣的,我不曉得『繼承』需要這樣的cost) Go準備完整的garbage-collected ,來足以應付併發與溝通問題。(以目前所學,各處聽到GO的gb機制多少令人詬病XD) Go是為了多核心機器所設計的語言。(沒錯,這點非常重要!) What is the status of the project? Go 是個開源的poject,有Google撐腰,version 1 是個長期支援的版本。 version 2 改天指日可待! What’s the origin of the mascot? (吉祥物,略) What is the history of the project? (歷史,略) Why are you creating a new language? 這裡說目前主要的程式語言,若達到簡單好上手(直譯式、弱型別)的,那麼就不能滿足安全又快速的條件(我想這是以事先編譯的角度來看)。 Go 想要達到簡單、安全又快速,可以處理併發、多核心的機器。 GO語言目標:在 單一一台機器上,可以快速與有效的執行龐大的程式 。 What are Go’s ancestors? Go 主要血統是C語言,但參雜很多語言的概念,還有新的。 What are the guiding principles in the design? (部份不太懂) 捨棄繼承,type就是純粹的type,而不用聲明type和type的關係(講繼承) 保持概念和原則的純粹,method -->實現任何類型; stru

[Go] 型態轉換 type convert

常用的型態轉換小筆記 int 轉 float64 float64(i) int64 轉 string i := int64(32) str := strconv.FormatInt(i, 10) 參數1 : 要轉的數字 參數2 : 指定進位制,10 >>> 10進位的意思,也可以帶入16 >>> 幫你轉成16進位,再變成字串 string 轉int64 s := "66" i, err := strconv.ParseInt(s, 10, 64) 參數1 : 要轉的字串 參數2 : 指定進位制 參數3 : 位元型態,64 >>> int64,32 >>> int32,8 >>> int8 string 轉 float64 i := "10.53" strconv.ParseFloat(i, 64) 參數1 : 要轉的字串 參數2 : 位元型態,64 >>> float64,32 >>> float32 float64 轉 string i := 23.957232 strconv.FormatFloat(i, ‘f’, 4, 64) 參數1 : 要轉的字串 參數2 : ‘b’ >>> 二進位表示 ’e’ >>> 指數表示(科學符號) ‘E’ >>> 同’e’ ‘f’ >>> 不使用科學符號 ’g’ >>> 大指數表示(我不知道這啥) ‘G’ >>> 同’g’ 參數3 : 小數點後幾位 參數4 : bit-size,原本是float32帶32,float64,帶64 [100]byte 轉string s := string(byteArray[:]) []byte 轉string s := string(byteArray) 有趣的點是byte array 是無法直接轉成string,必須先轉成slice再到string,所以若原本是byte