.Net Config Transformation Online
Web.config Transformation Tester
JSON
JSON C# Class
JSON Query Online
JSON Format
YAML
Check
SQL Format
Format SQL Statements Online - sqlformat.org
(fin)
Web.config Transformation Tester
Format SQL Statements Online - sqlformat.org
(fin)
Asp.Net Core 的 Life Cycle 由 Program.cs
的 main
方法開始(是的,就如同其它一般的程式),
在 WebHostBuilder
中的 ConfigureLogging
可以提供彈性讓你設定屬於你的 LoggerProvider,
不論是微軟提供、知名的第三方套件或是你手工自已刻一個,大致你的程式碼會如下
1 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => |
而在 Controller 或其它 Module 間,你只要透過建構子注入 logger 實體就可以實現 log 的功能
1 | public HomeController(ILogger<HomeController> logger) |
如果你沒有呼叫 ConfigureLogging
預設的行為如下述.
The default project template calls CreateDefaultBuilder
, which adds the following logging providers:
1 | public static void Main(string[] args) |
範例說明:在建構子中注入 ILogger
實體,運行網站後連到 Home\Index 頁面,並觀察 Console
1 | public class HomeController : Controller |
結果如下,可以發現 LogLevel.None
、LogLevel.Trace
與 LogLevel.Warning
並未出現在 Console 資訊當中
1 | info: Marsen.NetCore.Site.Controllers.HomeController[0] |
LogLevel說明了 None
的意義就是不記錄任何訊息,
Enum | Level | Description |
---|---|---|
Trace | 0 | Logs that contain the most detailed messages. These messages may contain sensitive application data. These messages are disabled by default and should never be enabled in a production environment. |
Debug | 1 | Logs that are used for interactive investigation during development. These logs should primarily contain information useful for debugging and have no long-term value. |
Information | 2 | Logs that track the general flow of the application. These logs should have long-term value. |
Warning | 3 | Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the application execution to stop. |
Error | 4 | Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a failure in the current activity, not an application-wide failure. |
Critical | 5 | Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires immediate attention. |
None | 6 | Not used for writing log messages. Specifies that a logging category should not write any messages. |
Log 的作用範圍會受 appsettings.json
影響,
另外要注意 appsettings.json 的載入順序.
1 | "Logging": { |
如同 Console
的行為一般,可以在 Visual Studio 的輸出(Output)>偵錯(Debug)視窗中,查詢到記錄。
如同官方文件所說,我下載了 PerfView
,
如下圖作了設定,
不過我並沒有取得記錄,
錯誤訊息如下
EventSource Microsoft-Extensions-Logging: Object reference not set to an instance of an object
暫時不打算深追查,
ETW 可以記錄的 Memory 、Disc IO 、CPU 等資訊,
其實與我想要的應用程式記錄有所差異,稍稍記錄一下以後也許用得到。
如果有人能留言給我一些方向,也是非常歡迎。
調整一下程式
1 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => |
這裡我使用 Microsoft.Extensions.Logging.EventLog
處理 EventLog 可以在 Event View 中看見記錄;
而 file log 我使用 Serilog.Extensions.Logging.File
, 特別要注意以下兩點
Elmah 在 Net 算是一個蠻方便的工具,有提供簡易介面、可以選擇用 File 或是 Database 方式作 Logging,
更重要是小弟我用了 4 年,順手就研究一下。
設定相當簡單, 在 Startup.cs
的 ConfigureServices
加入
1 | services.AddElmah<XmlFileErrorLog>(options => |
在 Configure
加入
1 | app.UseElmah(); |
要注意是使用 XmlFileErrorLog
時,要設定的 options 是 LogPath
而非 Path
,
其實使用 File 只能說是開發環境的暫時處置,真正的 Prodction 應該將 Log 放到專門的 Database 或是 Cloud Service 之中,
在這裡可以看見 Elmah 的行為與 Net Core 的行為並不一致,Log 與錯誤記錄本來就不該混為一談。
我想我要調整一下我的想法了,不過關於 Log 暫時就到此為止。
(fin)
上次在公司內部開始進行 Coding Dojo,在 FizzBuzz 的 Kata 嚐到了甜頭
但是下一道題目「Bowling」,卻卡住了。
我們有測試,也通過測試,但是卻寸步難行,
在重構上我們非常的弱,這裡的重構不是指一次性的全面翻掉,
而是逐步的、可靠的前進,
我想習得這樣的技能,因為現場的代碼腐敗的更加嚴重,
如果連 Kata 產生的代碼都不能優化,
那想對產品指手劃腳只不過是說幹話。
這是一本來自 Martin Fowler 的經典書籍,新版已經出了,而且是以 JavaScript
作為範例語言。
不過我手頭上借到的是以 Java
作為範例的板本。
第一個問題就是我找不到書中說的「線上範例」,
即使找到我也沒有 Java
的開發環境,所以心一橫就開始了改寫成 C#
的計劃
這部份比我想像中的簡單很多,兩個語言是相同類似的,
第 1 章,第一個案例
接下來只要照著書上一步一步作就會…覺得越來越沒 fu …
為什麼 ???
其實 Martin 大叔在書中有提到「為即將修改的程式建立可靠的測試…畢竟是人,可能會犯錯。所以我需要可靠的測試」。
沒 fu 的原因就是我沒加測試,即使重構了,我也不知道好壞。
沒有反饋是很糟糕的一件事。
那麼要怎麼加測試呢 ?
書上的案例我分析了一下,其實重構的目標只是一個單純的方法
會針對不同的情境回傳不同的字串。
簡單的說,我只要讓測試覆蓋這個方法就可以開始重構了,
我選擇 dotCover來檢驗我的覆蓋率。
選擇的原因很簡單,因為我買了 ReSharper,
其中就包含這個好用的工具。
試著投資一些金錢在工具上的回報是相當值得的。如果有更好用更便宜的工具也請介紹給我。
OS:課金真的能解決很多人生問題啊(茶)…
最後的結果,我開了一個分支包含了 100%的測試覆蓋率,
這樣就可以開開心心重構了,相信我有測試真得很有感覺。
重構的技法請自行看書,我只稍微作個記錄,有興趣可以 fork 回去玩。
在重構的過程中我儘可能讓步驟小(Baby Step),看我的 commit 歷程即可知道,但是最好可以自已作作看。
另外有一些心法,也稍作個記錄
第一章的範例完成後的結果大致如下
很帥氣的 100%啊,這樣的 code 測試覆蓋率 100 % 全綠燈,
而且完成了重構,根本是現場不可能出現的完全體程式碼!!!
代碼的部份我會放在最後的參考區塊。
下一步,我有沒有可能讓它更好?或是找出他的缺陷呢?
這個時候我想起了變異測試
還沒有實作過,來玩看看好了。
首先要選擇測試工具,這裡使用了Stryker Mutator,
但是注意只能用在 .Net Core 的版本
照著官網安裝完成後執行
1 | dotnet stryker |
跑下去竟然真的找到有存活的變異
這兩個變異存活的原因是類似的,
1 | double result = 2; |
變異點發生在 daysRented > 2
的判斷式之中,
現有的測試在變異發生(daysRented >= 2
)時,無法提出警訊,也就是測試上的不足。
不過依現有的邏輯,不論是進入 if
進行了加 0 運算,或是直接回傳 result,
都是等價的(回傳 2 ),目前還沒有想法怎麼強化我的測試,
希望有先進願意不嗇指點,實務上跟本沒在跑變異測試。
回歸一下我們當初 Kata 的目的:
事情沒有那麼簡單,比如說學習 Vim 的過程中,
我們的目的是增進開發速度,但是一開始反而會變慢,
一定要刻意的練習才能習得,
你必須擁有以下的能力。
彼此學習方面需要相當的軟技能,
溝通、尊重、謙虛…;這些一生的功課我就不贅言了。
Pair Programming 一半是 Pair 一半是 Programming;
而在進入 Programming 之前請搞懂你要作什麼。
同樣的在 TDD 的過程之中,我們沒有事先理好需求,
沒有想好作好需求分析,隨便選了測試案例就開始進行,
如果好好分析,是可以歸納出其中的邏輯,
甚至是理出 test case 的順序。
重要的是過程,但是我們太在乎結果,以致程式快速的腐敗。
甚至到了難以修改的狀態,僅管有測試保護,卻無法重構。
這是很好的一課,特別在這裡記錄一下。
(fin)
相關服務要雲端化,要將站台、資料等…遷移至 AWS,
這個案例需要將大量在 File Server 上的檔案(報表/單據/報告書等…)上傳至 S3
因為檔案數量相當的大,所以開發一個簡單的指令來執行。
打開 terminal 執行以下語法
1 | > aws configure |
依指示設定 Access key ID
與 Secret access key
,
這個資料需要具備一定的權限才能取得,如果權限不足請向你的 AWS 服務管理員申請。
1 | $bucketName = "********************-your_bucket_name" |
(fin)
記錄一下 Kata 的思路。
1 | 1 is 1 |
雖然可以把上面的案例濃縮到 4 種,
整除 3 是 Fizz、
整除 5 是 Buzz、
整除 3 又整除 5 是 FizzBuzz ,
不符合上述條件的都是原數字。
有沒有必要寫這麼多測試呢?
比如說 1、2、4 的測試是不是重複了?
日前 91 大有過類似的討論,
1 | 第一個 test case 挑最簡單的,讓你可以從紅燈變綠燈。驅動出你需要的產品代碼。 |
測試的不是只有「驅動開發」而已。
而好的程式碼,也不能只依靠測試。
我一開始就寫成這樣,所以後面的 2、4 案例也都會是綠燈。
1 | public class FizzBuzz |
考慮另一種情況,也許有的人第一個測試案例會寫成這樣
1 | public class FizzBuzz |
這時候就有可能需要靠 2、4 的測試案例來驅動程式碼的改變。
實際上並沒有,第一種寫法對我來說就夠 Baby Step 了。
1 | public string GetResult(int number) |
相信這是很好理解的,雖然我的案例是從 1、2、3 而來,
但是在我的腦海中已經思考好了這個程式碼的「餘數規則」,
實作出一個「餘數規則」後,程式碼應該很容易隨著測試案例變成下面這個樣子,
用一堆 if
檢查「餘數」然後回傳指定的「字串」,就是我們的「規則」。
這個時候的複雜度是 4 。
1 | public class FizzBuzz |
我儘量還原當初的想法,並記錄下來,
有許多值得改善的地方,換個順序重構起來就會更明快。
這一步真的非常的的小,我想大多數的人甚至會跳過這步驟的重構,
我只是把餘數檢查抽成私有方法,可以透過 Resharper
快速重構。
1 | public class FizzBuzz |
這裡我是作了一個舖墊,主要是我看到了 Fizz
與 Buzz
的字串重複出現在 FizzBuzz
,
我預計下一階段要讓 FizzBuzz
是透過組合產生,而不是寫死在程式之中。
特別要注意的事是,我為了產生 result 變數,必須在最後多作一次空字串的檢查,
這個時候的複雜度會達到 5 。
1 | public class FizzBuzz |
這個階段 ‘Fizz’ 與 ‘Buzz’ 在程式中只會出現一次,
15 的餘數檢查也被移除了,這時的複雜度是 4 ,
可惜的是我沒有意識到第三個 if
的明顯不同,
如果我能提早重構成 result = number.ToString();
後面的重構也許會更簡潔一點。
1 | public class FizzBuzz |
這是繼 FizzBuzz
後產生的第二個 Class,
算有指標意義,這裡原本的目的是想要消除 if
,
但無法一步到位,先試著把 Fizz 與 Buzz 的邏輯作分離,
一樣我只聚焦在 Fizz 與 Buzz 身上,
而忽略了 其它
的邏輯判斷,寫成了三元判斷除了變成一行外其實沒有其他好處。
1 | public class FizzRule |
1 | public class FizzBuzz |
一樣把 Buzz 的邏輯搬到新的 Class 中,
這裡故意用相同的方法名,是為了下一步要抽介面。
1 | public string GetResult(int number) |
終於抽出了介面,自已為聰明的把關鍵字抽離到了介面之中,
卻沒有考慮到真正的邏輯是組合 result 的行為仍然相依在 FizzBuzz
Class
1 | public interface IRule |
1 | public class FizzRule : IRule |
1 | public class BuzzRule : IRule |
準備好了 IRule ,就是要讓 FizzBuzz
與 FizzRule
以及 BuzzRule
解耦的階段了,
這步我踩得有小,可以更直接一點重構,
一樣的問題,我仍然沒有意識最後一個if(?:)
其實也是一種 IRule
,
也沒有意識到 result+=XXX
與 return YYY?number.ToString() : result;
其實應該是屬於 IRule
的一部份
這時的複雜度仍然是 4
1 | public class FizzBuzz |
自以為帥氣的完成重構,而且用 foreach
消除了重複的 if
…
實際上複雜度完全沒有下降。
關鍵的 result += rule.Word;
與return string.IsNullOrEmpty(result) ? number.ToString() : result;
我繼續忽視它。
1 | public class FizzBuzz |
參考 Martin 大叔的作法,把 foreach 變成 pipelines
光是這個作法就讓我的複雜度從 4 下降到 2 了,
此時,result += rule.Word;
與return string.IsNullOrEmpty(result) ? number.ToString() : result;
就顯得相當奇怪,第一個邏輯我認為應該放進實作IRule
的類別之中,
而第二個邏輯應該是一個未被實作的 Rule 。
1 | public class FizzBuzz |
終於將result += rule.Word;
的邏輯從 FizzBuzz
抽離到 IRule
之中,
再由各自的 Rule 實作,這個時候就會覺得 IRule.Check
與 IRule.Word
有點累贅,
基於 SOLID 原則,這部份邏輯甚至不該被揭露在 FizzBuzz
之中。
1 | public interface IRule |
1 | public class FizzBuzz |
終於加上 NormalRule
Class 了,裡面只有一個方法 Apply
,
這裡是為了將來的介面準備,我想讓 NormalRule 成為 IRule
的一部份,
不過可以看到的問題是,方法簽章並不一致。
1 | public class FizzBuzz |
在我的認知中,對 Production Code 修改介面是件危險的事,
這在 Kata 是可行的,但是在實際的 Production 恐怕就不夠 Baby Step 了,
我或許應該創造一個 IRuleV2 之類的介面,而不是直接修改 IRule
。
首先編譯會不過,這會趨動我去修改 FizzRule
與 BuzzRule
另外,這個時間點 IRule.Check
與 IRule.Word
作為 public 的資訊就顯得相當多餘了。
所以我會進一步將這些資訊從 IRule
介面中拿掉,
這也會使得 FizzBuzz
Class 產生 Error,趁這個時候把 .Where()
與 .ToList()
一併拿掉,
但是要記得將 IRule.Check
與 IRule.Word
包含至 IRule.Apply
之中。
1 | public interface IRule |
1 | public class FizzRule : IRule |
這裡讓 NormalRule
實作 IRule
介面,
實際上在上面幾步已經完成了,IRule
反而比較像一個標籤掛在 NormalRule
上,
如此一來,就能夠在 FizzBuzz
裡面透過 List<IRule>
統整所有的規則。
1 | public class FizzBuzz |
1 | public interface IRule |
作到這裡大概把我想作的東西都作掉了,if
散落在各個 Rules
裡面,
如果是 Production Code 我想我會使用 NameSpace 與專案資料夾再作進一步的整理吧。
最後把 FizzRule
與 BuzzRule
的 Check
與 Word
拿掉只是一點潔癖。
1 | public class FizzRule : IRule |
過程中一直考慮著想要拿掉所有if
,或是套用職責鏈(Chain of Responsibility Pattern)的 Pattern,
現在想想都有點走歪了方向,一再忽視責職的歸屬而讓後面的重構有點吃力,
不過透過 TDD 仍然讓程式碼重構到了一定的程度。
如果重來一次的話,我會選擇提早分離職責,
不過當中的取捨可能需要練習更多的 KATA 吧。
有人說這麼重構,會不會有點 Over Design 了,
我想說的是,反正是練習嘛,刻意練習到過頭也只是剛好而已,
如果不在練習時下點苦功,在戰場上用得出來嗎?
至少我的天賦而言,我應該是用不出來的。
文章貼出後,同事的回饋,可以使用 Aggregate
取代 Foreach
,
程式碼可以更加精鍊。
1 | public class FizzBuzz |
把 r、n 這類較沒意義的命名改成 input 與 rule,
單純是為了讓 Aggregate
的可讀性較高一些。
接下來這個異動的幅度較大,實務上我不會這樣作,
讓 Apply
的方法簽章順序與 Aggregate
一樣把 input
String 放在最前面,
真的真的非常沒有必要,因為會異動到介面。
1 | public class FizzBuzz |
(fin)
在上 91 大的(熱血 Coding Dojo 第一梯次)的課程中,
我一直在思索一件事,為什麼我作不到呢?
我不希望只是上了課之後,「喔喔喔 我好興奮啊…」就結束了,
所以馬上找了一起上課的兩個同事開了個簡單的 Retro
我只有一個問題,
「如果你覺得這堂課有效的話,我們要作什麼 才能帶來改變呢 ?」
我們簡單的作了一個決定,我們要在公司內部建立一個 Dojo
並且簡單的訂定了三個目標
這三個東西都是在課堂上學習到的,幸運得是我們當中有兩位已經會基本的 Vim 指令,
當然也各有各的問題,ex: 不熟悉英打、沒有 Reshaper 、找不到共同的時間等…
總而言之,我們就這樣開始了。
第一個 Kata 是很重要的,Coding Dojo 提供我們一些選擇,
Tennis Game 與 Poker Hand 都是很好的題目,
但是新手上路,我們選了一個簡單的 Fizz Buzz 當作練習題目。
Fizz Buzz 的需求分析是很簡單的,
Sample Case:
1 | 1 → 1 |
首先是時間,專案很忙碌,不是所有的人都有空,
我要怎麼擠出時間 ?
每天都練習 KATA,每次 30 分鐘;
每天約定一個時間 30 分鐘,30 分鐘到就強制結束,
不論是中午的 30 分鐘,或是下班前的 30 分鐘,
找一個時間只要有兩個人的時間 OK 就進行 。
輪流當 Driver 與 Navigator ,時間設定 5 分鐘,
一樣時間到就換手。
1 | 嚴格執行 TimeBox 真的是一件很折磨人的事情, |
很幸運的,一直到過農曆年我們都沒有中斷,
設定 TimeBox 也確實有讓參與的人提昇,
包含「重構的技巧」、「打字」、「TDD」與「Vim」,
也有人分享工具,或是小技巧,
這達到我們彼此學習的目的。
ci
或是 AceJump 小工具。我們開發者真的太有自信,在 KATA 過程出現的問題,
如果放到開發現場的規模,基本上就是災難,
而實際上也是每天發生。
在時限的壓力下,你不能作出多完美的設計,
但是你可以透過測試作出足夠好的設計,
測試的保護可以幫助你提早發現
一直以來有那麼多讀書會,上了那麼多課,
也有外訓內訓,結果卻是不了了之,
要怎麼証明理論有效 ?
要怎麼導入開發現場 ?
我不是本科系畢業,但在軟體開發上也有 7、8 年的經驗,
軟體的經典書籍也看過不少,
不論是免費的社群活動或是上萬元的課程,
相關的課也上了不少。
學習單一語言的特性或是設計模式、物件導向到工程上的 Code Review、Pair Programming、TDD 諸如此類等…
不能說沒有幫助,但總覺得現實與書上的理想好遠啊…
我以為我懂了,其實我根本不懂。
技術不斷推陳出新,追不勝追,
常常工作完後研究或是練習到半夜,
但是沒什麼效果,或在實務上根本用不到
真得很有事倍功半的無力感。
在工作上的產品或專案永遠都有緊急又重要的事要作,
人家的艾森豪矩陣有四個象限,你永遠只有一個象限,
生活上各種的壓力與瑣事,變成了種惡性循環,
像個泥沼一般,無法提昇所以下沉,下沉了更無法提昇。
這個小小實驗,就像是整個開發現場的濃縮版,
現場很多問題不是沒有解答,
但是常常一句「理論上是,但是…」,然後就沒有然後了。
我們太習慣短解,太過自信,讓不好的事情重複發生,
然後覺得自已很忙碌,很有價值感,
但是沒有任何改變。
這個實驗我會繼續下去,期待能有好的結果,並帶來一些變化。
(fin)
活動連結 - 熱血 Coding Dojo - 第一梯次(活動已結束)
講師 : Joey Chen
範例語言 : C#
最近覺得寫程式真的是一種造業,創造就業機會。
與善人居,如入芝蘭之室,久而不聞其香,即與之化矣;
與不善人居,如入鮑魚之肆,久而不聞其臭。
雖很想推熱血 Coding Dojo - 第二梯次,不過大概已經完售了。
(fin)
最近開始學 Docker, 這個神器大概在 C 社時期就有聽過了,
不過一直沒有機會在實務上接觸,雖然有自已摸一點,但就只有皮毛而已,
在 A 社有機會由同事開課,並提供 EC2 作實驗,就趁這個機會作一點深入的學習。
一開始有一個很天真的想法,我想在 Windows 內建的 Linux 子系統 Ubantu 安裝 Docker,
沒想到最後是脫褲子放屁,不過過程蠻有趣的,稍微記錄一下。
Windows 10 安裝 Ubantu
在 Ubantu 安裝 Docker
更新 apt-get
1 | sudo apt-get update |
允許 apt-get 透過 https
1 | sudo apt-get install \ |
加入 Docker 官方 GPG KEY
1 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - |
然後可以驗証一下
1 | sudo apt-key fingerprint 0EBFCD88 |
加入 Docker 的 apt-repository
1 | sudo add-apt-repository \ |
再次更新 apt-get
1 | sudo apt-get update |
安裝 Docker CE
1 | sudo apt-get install docker-ce |
Run Docker
1 | sudo docker container run hello-world |
我都會失敗如下
1 | docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. |
Windows 上要安裝 Docker for Windows
勾選 Docker for Windows → Setting → Expose Daemon on tcp://localhost:2375 Without TLS
回到 Ubantu , 執行以下命令
指定 Docker Host 在路徑
1 | docker -H localhost:2375 images |
如果不想每次指定的話…請參考以下命令
1 | export DOCKER_HOST=localhost:2375 |
(fin)
查詢指定 Table 目前的索引值
DBCC CHECKIDENT (yourtable)
Example
1 | USE AdventureWorks2012; |
重新建立你的索引值
DBCC CHECKIDENT (yourtable, reseed, new index)
1 | USE AdventureWorks2012; |
(fin)
REST Client 是一套 Visual Studio Code 的套件。
可以讓你不離開編輯器(Visual Studio Code)的情況下,發送一些 Request。
使用方法可以參考最後的聯結,本文僅介紹 Code Gen 的功能。
取得 Request 連結資訊,這個部份可以直接從瀏覽器取得
大致上如下:
1 | GET https://***.****.com.my/Invoice/DownloadMyInvoicePdf?shopId=44&tradesOrderGroupCode=MG180929L00002 |
Ctrl+P,輸入 >
,找到 Rest Client: Generate Code Snippet
選擇你的語言。
(fin)