[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: thangchung\nopen_collective: cleancodedotnet\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with a single custom sponsorship URL\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# Merge with changes from client ignore\n\n# dependencies\n/node_modules\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n**/*log.txt\n/.vscode\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Thang Chung\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Program.cs",
    "content": "using System;\n\nnamespace CleanCodeDotNet\n{\n    internal class Program\n    {\n        private static void Main(string[] args)\n        {\n            Console.WriteLine(\"This is C# repository.\");\n        }\n    }\n}"
  },
  {
    "path": "README-zh.md",
    "content": "# 适用于 .NET/.NET Core 的代码整洁之道\n\n如果您喜欢 `clean-code-dotnet` 项目，或者它对于您所帮助，请给这个仓库一个小星星 :star: 。这不仅会激励我们的 .NET 社区，也会帮助全世界的 .NET 开发者提升编写优质代码的技能。非常感谢您 :+1:\n\n请查看我的[博客](https://medium.com/@thangchung)，或者在 [Twitter](https://twitter.com/thangchung) 上联系我！\n\n# 目录\n\n- [适用于 .NET/.NET Core 的代码整洁之道](#%e9%80%82%e7%94%a8%e4%ba%8e-netnet-core-%e7%9a%84%e4%bb%a3%e7%a0%81%e6%95%b4%e6%b4%81%e4%b9%8b%e9%81%93)\n- [目录](#%e7%9b%ae%e5%bd%95)\n- [介绍](#%e4%bb%8b%e7%bb%8d)\n- [.NET 中的整洁代码](#net-%e4%b8%ad%e7%9a%84%e6%95%b4%e6%b4%81%e4%bb%a3%e7%a0%81)\n  - [命名](#%e5%91%bd%e5%90%8d)\n  - [变量](#%e5%8f%98%e9%87%8f)\n  - [函数](#%e5%87%bd%e6%95%b0)\n  - [对象和数据结构](#%e5%af%b9%e8%b1%a1%e5%92%8c%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84)\n  - [类](#%e7%b1%bb)\n  - [SOLID](#solid)\n  - [测试](#%e6%b5%8b%e8%af%95)\n  - [并发](#%e5%b9%b6%e5%8f%91)\n  - [异常处理](#%e5%bc%82%e5%b8%b8%e5%a4%84%e7%90%86)\n  - [格式化](#%e6%a0%bc%e5%bc%8f%e5%8c%96)\n  - [注释](#%e6%b3%a8%e9%87%8a)\n- [其它关于代码整洁之道的资源](#%e5%85%b6%e5%ae%83%e5%85%b3%e4%ba%8e%e4%bb%a3%e7%a0%81%e6%95%b4%e6%b4%81%e4%b9%8b%e9%81%93%e7%9a%84%e8%b5%84%e6%ba%90)\n  - [其它代码整洁之道列表](#%e5%85%b6%e5%ae%83%e4%bb%a3%e7%a0%81%e6%95%b4%e6%b4%81%e4%b9%8b%e9%81%93%e5%88%97%e8%a1%a8)\n  - [工具](#%e5%b7%a5%e5%85%b7)\n  - [表格](#%e8%a1%a8%e6%a0%bc)\n- [贡献者](#%e8%b4%a1%e7%8c%ae%e8%80%85)\n- [支持者](#%e6%94%af%e6%8c%81%e8%80%85)\n- [赞助商](#%e8%b5%9e%e5%8a%a9%e5%95%86)\n- [许可证](#%e8%ae%b8%e5%8f%af%e8%af%81)\n\n# 介绍\n\n![Humorous image of software quality estimation as a count of how many expletives you shout when reading code](http://www.osnews.com/images/comics/wtfm.jpg)\n\n软件工程原则，是来自于 Robert C. Martin 的一本书 [_Clean Code_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882), 就 .NET/.NET Core 而言，它并不是编码风格指南，而是为了指导开发者能够编写出具有可读性、可重用性和可重构的 .NET/.NET Core 程序。\n\n这里面描述的每一项原则并不是被严格遵守的，并且支持者也相对更少。这些仅仅是指导指南，但这些指南是 _Clean Code_. 作者们多年经验的智慧结晶。\n\n灵感来源于 [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript) 和 [clean-code-php](https://github.com/jupeter/clean-code-php)。\n\n# .NET 中的整洁代码\n\n## 命名\n\n<details>\n  <summary><b>避免使用随意的命名</b></summary>\n\n代码中采用优雅而不随意的命名方式会易于被更多的开发者采用，命名名称应反映出它的作用及对应的上下文关系\n\n**Bad:**\n\n```csharp\nint d;\n```\n\n**Good:**\n\n```csharp\nint daySinceModification;\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>避免使用误导性名称</b></summary>\n\n给变量定义的名称需要反映出该变量的用途\n\n**Bad:**\n\n```csharp\nvar dataFromDb = db.GetFromService().ToList();\n```\n\n**Good:**\n\n```csharp\nvar listOfEmployee = _employeeService.GetEmployees().ToList();\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>避免使用匈牙利命名法</b></summary>\n\n匈牙利命名法会在已定义的变量加上类型前缀，这是毫无意义的，因为现代化的继承开发环境会自动标识变量类型。\n\n**Bad:**\n\n```csharp\nint iCounter;\nstring strFullName;\nDateTime dModifiedDate;\n```\n\n**Good:**\n\n```csharp\nint counter;\nstring fullName;\nDateTime modifiedDate;\n```\n匈牙利命名发也不应该用于参数命令。\n\n**Bad:**\n\n```csharp\npublic bool IsShopOpen(string pDay, int pAmount)\n{\n    // some logic\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsShopOpen(string day, int amount)\n{\n    // some logic\n}\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用一致的大写方式</b></summary>\n\n大写式命名可以向你暴露一些变量、功能等信息。这个规则具有主观性，所以你们团队可以选择你们喜欢的方式，但只要保持一致即可。\n\n**Bad:**\n\n```csharp\nconst int DAYS_IN_WEEK = 7;\nconst int daysInMonth = 30;\n\nvar songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' };\nvar Artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' };\n\nbool EraseDatabase() {}\nbool Restore_database() {}\n\nclass animal {}\nclass Alpaca {}\n```\n\n**Good:**\n\n```csharp\nconst int DaysInWeek = 7;\nconst int DaysInMonth = 30;\n\nvar songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' };\nvar artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' };\n\nbool EraseDatabase() {}\nbool RestoreDatabase() {}\n\nclass Animal {}\nclass Alpaca {}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用可读的命名方式</b></summary>\n\n当变量和函数的命名不可读时，研究它们的函数是需要花费一些时间的。\n\n**Bad:**\n\n```csharp\npublic class Employee\n{\n    public Datetime sWorkDate { get; set; } // what the heck is this\n    public Datetime modTime { get; set; } // same here\n}\n```\n\n**Good:**\n\n```csharp\npublic class Employee\n{\n    public Datetime StartWorkingDate { get; set; }\n    public Datetime ModificationTime { get; set; }\n}\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用驼峰命名法</b></summary>\n\n针对变量和函数应采用 [驼峰命名法](https://en.wikipedia.org/wiki/Camel_case) \n\n**Bad:**\n\n```csharp\nvar employeephone;\n\npublic double CalculateSalary(int workingdays, int workinghours)\n{\n    // some logic\n}\n```\n\n**Good:**\n\n```csharp\nvar employeePhone;\n\npublic double CalculateSalary(int workingDays, int workingHours)\n{\n    // some logic\n}\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用概括性命名</b></summary>\n\n那些阅读你代码的人通常也是开发者，合理组织每个页面内容的的命名，让每个人都能轻易理解你想表达式的意思，这样我们就不用花费时间去想每个人解释里面变量、函数的功能。\n\n**Good**\n\n```csharp\npublic class SingleObject\n{\n    // create an object of SingleObject\n    private static SingleObject _instance = new SingleObject();\n\n    // make the constructor private so that this class cannot be instantiated\n    private SingleObject() {}\n\n    // get the only object available\n    public static SingleObject GetInstance()\n    {\n        return _instance;\n    }\n\n    public string ShowMessage()\n    {\n        return \"Hello World!\";\n    }\n}\n\npublic static void main(String[] args)\n{\n    // illegal construct\n    // var object = new SingleObject();\n\n    // Get the only object available\n    var singletonObject = SingleObject.GetInstance();\n\n    // show the message\n    singletonObject.ShowMessage();\n}\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n## 变量\n\n<details>\n  <summary><b>避免嵌套太深，及时返回</b></summary>\n\n过多的 `if else` 段会让代码变得晦涩难懂，**简洁明了优于暗藏玄机**。\n\n**Bad:**\n\n```csharp\npublic bool IsShopOpen(string day)\n{\n    if (!string.IsNullOrEmpty(day))\n    {\n        day = day.ToLower();\n        if (day == \"friday\")\n        {\n            return true;\n        }\n        else if (day == \"saturday\")\n        {\n            return true;\n        }\n        else if (day == \"sunday\")\n        {\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n    }\n    else\n    {\n        return false;\n    }\n\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsShopOpen(string day)\n{\n    if (string.IsNullOrEmpty(day))\n    {\n        return false;\n    }\n\n    var openingDays = new[] { \"friday\", \"saturday\", \"sunday\" };\n    return openingDays.Any(d => d == day.ToLower());\n}\n```\n\n**Bad:**\n\n```csharp\npublic long Fibonacci(int n)\n{\n    if (n < 50)\n    {\n        if (n != 0)\n        {\n            if (n != 1)\n            {\n                return Fibonacci(n - 1) + Fibonacci(n - 2);\n            }\n            else\n            {\n                return 1;\n            }\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        throw new System.Exception(\"Not supported\");\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic long Fibonacci(int n)\n{\n    if (n == 0)\n    {\n        return 0;\n    }\n\n    if (n == 1)\n    {\n        return 1;\n    }\n\n    if (n > 50)\n    {\n        throw new System.Exception(\"Not supported\");\n    }\n\n    return Fibonacci(n - 1) + Fibonacci(n - 2);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>避免主观映射</b></summary>\n\n不要迫使编译器强行翻译你的代码含义 **显式优于隐式**.\n\n**Bad:**\n\n```csharp\nvar l = new[] { \"Austin\", \"New York\", \"San Francisco\" };\n\nfor (var i = 0; i < l.Count(); i++)\n{\n    var li = l[i];\n    DoStuff();\n    DoSomeOtherStuff();\n\n    // ...\n    // ...\n    // ...\n    // Wait, what is `li` for again?\n    Dispatch(li);\n}\n```\n\n**Good:**\n\n```csharp\nvar locations = new[] { \"Austin\", \"New York\", \"San Francisco\" };\n\nforeach (var location in locations)\n{\n    DoStuff();\n    DoSomeOtherStuff();\n\n    // ...\n    // ...\n    // ...\n    Dispatch(location);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>避免使用魔法字符串</b></summary>\n\n魔法字符串是指直接在应用程序代码中指定的字符串值，这些字符串对会应用程序的行为有所影响。通常，此类字符串最终会在系统中重复使用，并且由于它们无法使用重构工具自动更新，因此当对某些字符串进行更改时，它们将成为常见的 Bug 来源，而不是其他字符串。\n\n**Bad**\n\n```csharp\nif (userRole == \"Admin\")\n{\n    // logic in here\n}\n```\n\n**Good**\n\n```csharp\nconst string ADMIN_ROLE = \"Admin\"\nif (userRole == ADMIN_ROLE)\n{\n    // logic in here\n}\n```\n\n使用这种方式的话，我们只需要改变关键的地方，其它地方也就会跟着改变。\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>不要引入不必要的上下文</b></summary>\n\n如果你的类/对象名称已经告诉了你一些信息，不要在其内部定义重复定义该变量名称。\n\n**Bad:**\n\n```csharp\npublic class Car\n{\n    public string CarMake { get; set; }\n    public string CarModel { get; set; }\n    public string CarColor { get; set; }\n\n    //...\n}\n```\n\n**Good:**\n\n```csharp\npublic class Car\n{\n    public string Make { get; set; }\n    public string Model { get; set; }\n    public string Color { get; set; }\n\n    //...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用有意义和可读的变量名称</b></summary>\n\n**Bad:**\n\n```csharp\nvar ymdstr = DateTime.UtcNow.ToString(\"MMMM dd, yyyy\");\n```\n\n**Good:**\n\n```csharp\nvar currentDate = DateTime.UtcNow.ToString(\"MMMM dd, yyyy\");\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>对相同类型的变量使用相同的名称</b></summary>\n\n**Bad:**\n\n```csharp\nGetUserInfo();\nGetUserData();\nGetUserRecord();\nGetUserProfile();\n```\n\n**Good:**\n\n```csharp\nGetUser();\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用可搜索的名称（第 1 部分）</b></summary>\n\n我们阅读的代码比我们的写的代码要多。我们写的代码应该具有可读性和可搜索性，这个很重要。使用不合适的命令方式会影响我们对程序的理解，这会伤害到阅读者，让你的命名可搜索。\n\n**Bad:**\n\n```csharp\n// What the heck is data for?\nvar data = new { Name = \"John\", Age = 42 };\n\nvar stream1 = new MemoryStream();\nvar ser1 = new DataContractJsonSerializer(typeof(object));\nser1.WriteObject(stream1, data);\n\nstream1.Position = 0;\nvar sr1 = new StreamReader(stream1);\nConsole.Write(\"JSON form of Data object: \");\nConsole.WriteLine(sr1.ReadToEnd());\n```\n\n**Good:**\n\n```csharp\nvar person = new Person\n{\n    Name = \"John\",\n    Age = 42\n};\n\nvar stream2 = new MemoryStream();\nvar ser2 = new DataContractJsonSerializer(typeof(Person));\nser2.WriteObject(stream2, data);\n\nstream2.Position = 0;\nvar sr2 = new StreamReader(stream2);\nConsole.Write(\"JSON form of Data object: \");\nConsole.WriteLine(sr2.ReadToEnd());\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用可搜索的名称（第 2 部分）</b></summary>\n\n**Bad:**\n\n```csharp\nvar data = new { Name = \"John\", Age = 42, PersonAccess = 4};\n\n// What the heck is 4 for?\nif (data.PersonAccess == 4)\n{\n    // do edit ...\n}\n```\n\n**Good:**\n\n```csharp\npublic enum PersonAccess : int\n{\n    ACCESS_READ = 1,\n    ACCESS_CREATE = 2,\n    ACCESS_UPDATE = 4,\n    ACCESS_DELETE = 8\n}\n\nvar person = new Person\n{\n    Name = \"John\",\n    Age = 42,\n    PersonAccess= PersonAccess.ACCESS_CREATE\n};\n\nif (person.PersonAccess == PersonAccess.ACCESS_UPDATE)\n{\n    // do edit ...\n}\n```\n\n**[⬆ Back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用解释型变量</b></summary>\n\n**Bad:**\n\n```csharp\nconst string Address = \"One Infinite Loop, Cupertino 95014\";\nvar cityZipCodeRegex = @\"/^[^,\\]+[,\\\\s]+(.+?)\\s*(\\d{5})?$/\";\nvar matches = Regex.Matches(Address, cityZipCodeRegex);\nif (matches[0].Success == true && matches[1].Success == true)\n{\n    SaveCityZipCode(matches[0].Value, matches[1].Value);\n}\n```\n\n**Good:**\n\nDecrease dependence on regex by naming subpatterns.\n\n```csharp\nconst string Address = \"One Infinite Loop, Cupertino 95014\";\nvar cityZipCodeWithGroupRegex = @\"/^[^,\\]+[,\\\\s]+(?<city>.+?)\\s*(?<zipCode>\\d{5})?$/\";\nvar matchesWithGroup = Regex.Match(Address, cityZipCodeWithGroupRegex);\nvar cityGroup = matchesWithGroup.Groups[\"city\"];\nvar zipCodeGroup = matchesWithGroup.Groups[\"zipCode\"];\nif(cityGroup.Success == true && zipCodeGroup.Success == true)\n{\n    SaveCityZipCode(cityGroup.Value, zipCodeGroup.Value);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用默认参数而不是条件判断</b></summary>\n\n**Not good:**\n\n这样并不好，因为 `breweryName` 可能为 `NULL`。\n\n这种方式在之前的版本更容易理解，它能很好地控制变量的值。\n\n```csharp\npublic void CreateMicrobrewery(string name = null)\n{\n    var breweryName = !string.IsNullOrEmpty(name) ? name : \"Hipster Brew Co.\";\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic void CreateMicrobrewery(string breweryName = \"Hipster Brew Co.\")\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 函数\n\n\n<details>\n  <summary><b>避免副作用</b></summary>\n\n如果函数除了获取一个值并且返回另一个值之外执行了一些操作，则会产生副作用。副作用可能是文件写入，修改一些全局变量，或者意外地向外部暴露了数据。\n\n在某些情况下，你的程序确实需要一些副作用，像上述示例一样，你可能需要文件写入，当集中执行这些操作时，并没有多个函数或类来支持写入特定文件，这时可以通过一个服务来执行这个副作用，这是唯一的一种方法。\n\n关键点是要避免一些常见的陷阱。比如没有任何结构关联的对象间的状态共享。使用任何可写入的可变数据类型，以及不确定的副作用发生的位置。如果你能意识到这一点的话，会比周围其他程序员更高兴一些。\n\n**Bad:**\n\n```csharp\n// Global variable referenced by following function.\n// If we had another function that used this name, now it'd be an array and it could break it.\nvar name = 'Ryan McDermott';\n\npublic string SplitIntoFirstAndLastName()\n{\n   return name.Split(\" \");\n}\n\nSplitIntoFirstAndLastName();\n\nConsole.PrintLine(name); // ['Ryan', 'McDermott'];\n```\n\n**Good:**\n\n```csharp\npublic string SplitIntoFirstAndLastName(string name)\n{\n    return name.Split(\" \");\n}\n\nvar name = 'Ryan McDermott';\nvar newName = SplitIntoFirstAndLastName(name);\n\nConsole.PrintLine(name); // 'Ryan McDermott';\nConsole.PrintLine(newName); // ['Ryan', 'McDermott'];\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>避免非条件</b></summary>\n\n**Bad:**\n\n```csharp\npublic bool IsDOMNodeNotPresent(string node)\n{\n    // ...\n}\n\nif (!IsDOMNodeNotPresent(node))\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsDOMNodePresent(string node)\n{\n    // ...\n}\n\nif (IsDOMNodePresent(node))\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>避免多条件</b></summary>\n\n这似乎是一个不现实的要求，第一次听到这个的时候，大多数人说，“如果没有 `if` 语句 我怎么能实现一些功能呢？” 第二个问题通常是，\"那很好，但我为什么要这么做呢？\" 答案是我们之前学到的整洁代码概念：函数应该只做有一件事，当你的类和函数具有 \"if\" 语句时，您会告诉用户您的函数执行多个事情。记住，只做一件事。\n\n**Bad:**\n\n```csharp\nclass Airplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        switch (_type)\n        {\n            case '777':\n                return GetMaxAltitude() - GetPassengerCount();\n            case 'Air Force One':\n                return GetMaxAltitude();\n            case 'Cessna':\n                return GetMaxAltitude() - GetFuelExpenditure();\n        }\n    }\n}\n```\n\n**Good:**\n\n```csharp\ninterface IAirplane\n{\n    // ...\n\n    double GetCruisingAltitude();\n}\n\nclass Boeing777 : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude() - GetPassengerCount();\n    }\n}\n\nclass AirForceOne : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude();\n    }\n}\n\nclass Cessna : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude() - GetFuelExpenditure();\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>避免类型检查（第 1 部分）</b></summary>\n\n**Bad:**\n\n```csharp\npublic Path TravelToTexas(object vehicle)\n{\n    if (vehicle.GetType() == typeof(Bicycle))\n    {\n        (vehicle as Bicycle).PeddleTo(new Location(\"texas\"));\n    }\n    else if (vehicle.GetType() == typeof(Car))\n    {\n        (vehicle as Car).DriveTo(new Location(\"texas\"));\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic Path TravelToTexas(Traveler vehicle)\n{\n    vehicle.TravelTo(new Location(\"texas\"));\n}\n```\n\nor\n\n```csharp\n// pattern matching\npublic Path TravelToTexas(object vehicle)\n{\n    if (vehicle is Bicycle bicycle)\n    {\n        bicycle.PeddleTo(new Location(\"texas\"));\n    }\n    else if (vehicle is Car car)\n    {\n        car.DriveTo(new Location(\"texas\"));\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>避免类型检查（第 2 部分）</b></summary>\n\n**Bad:**\n\n```csharp\npublic int Combine(dynamic val1, dynamic val2)\n{\n    int value;\n    if (!int.TryParse(val1, out value) || !int.TryParse(val2, out value))\n    {\n        throw new Exception('Must be of type Number');\n    }\n\n    return val1 + val2;\n}\n```\n\n**Good:**\n\n```csharp\npublic int Combine(int val1, int val2)\n{\n    return val1 + val2;\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>避免在方法参数中设置标志</b></summary>\n\n标志指示着这个方法有更多的职责。最好的办法是单一职责原则，如果布尔参数会往函数中会添加多个职责，那么就将这个函数拆分为两个。\n\n**Bad:**\n\n```csharp\npublic void CreateFile(string name, bool temp = false)\n{\n    if (temp)\n    {\n        Touch(\"./temp/\" + name);\n    }\n    else\n    {\n        Touch(name);\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic void CreateFile(string name)\n{\n    Touch(name);\n}\n\npublic void CreateTempFile(string name)\n{\n    Touch(\"./temp/\"  + name);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>不要编写全局函数</b></summary>\n\n> 还没完\n\n在很多语言中，污染全局是一种差的实践方式，因为你可能会与其它库发送冲突，并且你的 API 用户在生产环境下获取一个异常将毫不明智。让我们一起思考一个示例：如果想要配置数组该如何处理。你可以编写一个像 `Config()` 的全局函数，但它可能会与另一个尝试执行相同操作的库发生冲突。\n\n**Bad:**\n\n```csharp\npublic string[] Config()\n{\n    return  [\n        \"foo\" => \"bar\",\n    ]\n}\n```\n\n**Good:**\n\n```csharp\nclass Configuration\n{\n    private string[] _configuration = [];\n\n    public Configuration(string[] configuration)\n    {\n        _configuration = configuration;\n    }\n\n    public string[] Get(string key)\n    {\n        return (_configuration[key]!= null) ? _configuration[key] : null;\n    }\n}\n```\n\n加载配置并创建配置实例 `Configuration`\n\n```csharp\nvar configuration = new Configuration(new string[] {\n    \"foo\" => \"bar\",\n});\n```\n\n你现在在应用程序中必须使用 `Configuration` 的实例\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>不要使用单例模式</b></summary>\n\n单例模式是一种 [反模式](https://en.wikipedia.org/wiki/Singleton_pattern). 根据 from Brian Button 的描述:\n\n1. 它们通常作为一个 **全局实例** 存在，为什么这样不好？因为你在你的程序代码中 **隐藏依赖项**，而不是通过接口来暴露它们，为了避免对象传递而将其设置为全局的方式是一种 [code smell](https://en.wikipedia.org/wiki/Code_smell)。\n2. 它们违反了[单一职责原则](#single-responsibility-principle-srp)：**它们控制了自己的对象创建和生命周期**\n3. 它们本质上会导致代码紧密地 [耦合](https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29)，这使得在许多情况下，在测试环境下模拟它们异常困难。\n4. 它们在应用程序的生存期内会携带状态。另一点需要测试，因为[你最终可能会得到一种情况，即测试需要排序]，这违背了单元测试的原则。为什么？因为每个单元测试相互独立。\n\n这儿也有一些 [Misko Hevery](http://misko.hevery.com/about/)  关于 [root of problem](http://misko.hevery.com/2008/08/25/root-cause-of-singletons/) 很不错的想法。\n\n**Bad:**\n\n```csharp\nclass DBConnection\n{\n    private static DBConnection _instance;\n\n    private DBConnection()\n    {\n        // ...\n    }\n\n    public static GetInstance()\n    {\n        if (_instance == null)\n        {\n            _instance = new DBConnection();\n        }\n\n        return _instance;\n    }\n\n    // ...\n}\n\nvar singleton = DBConnection.GetInstance();\n```\n\n**Good:**\n\n```csharp\nclass DBConnection\n{\n    public DBConnection(IOptions<DbConnectionOption> options)\n    {\n        // ...\n    }\n\n    // ...\n}\n```\n\n创建一个 `DBConnection` 实例，并通过 [Option pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.1) 来进行配置\n\n```csharp\nvar options = <resolve from IOC>;\nvar connection = new DBConnection(options);\n```\n\n现在，你在你的应用程序中必须使用 `DBConnection` 的类型实例\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>函数参数（2个或者更少最佳）</b></summary>\n\n限制函数参数的数量非常重要，因为它使测试函数变得更加容易。拥有三个以上会导致组合爆炸，您必须使用每个单独的参数测试大量不同用例。\n\n无参是理想的情况。一个或两个参数是可以的，三个应该避免，超过的话应该合并。通常，如果您有两个以上参数，则函数尝试执行的操作太多。大多数时候，一个更高级别的对象将足以作为一个参数。\n\n**Bad:**\n\n```csharp\npublic void CreateMenu(string title, string body, string buttonText, bool cancellable)\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic class MenuConfig\n{\n    public string Title { get; set; }\n    public string Body { get; set; }\n    public string ButtonText { get; set; }\n    public bool Cancellable { get; set; }\n}\n\nvar config = new MenuConfig\n{\n    Title = \"Foo\",\n    Body = \"Bar\",\n    ButtonText = \"Baz\",\n    Cancellable = true\n};\n\npublic void CreateMenu(MenuConfig config)\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>一个函数只应该做一件事情</b></summary>\n\n在软件开发过程中，这是一个很重要的原则。当函数要做的事情超过一件的时候就很难组合到一起进行测试，这是因为，当你可以将一个函数隔离为一个操作时，可以轻松的进行重构，并且能够过得更多清晰明确的信息。如果你在这份指南中只学会到了这一点，那么你将比其他开发者更领先一些。\n\n**Bad:**\n\n```csharp\npublic void SendEmailToListOfClients(string[] clients)\n{\n    foreach (var client in clients)\n    {\n        var clientRecord = db.Find(client);\n        if (clientRecord.IsActive())\n        {\n            Email(client);\n        }\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic void SendEmailToListOfClients(string[] clients)\n{\n    var activeClients = GetActiveClients(clients);\n    // Do some logic\n}\n\npublic List<Client> GetActiveClients(string[] clients)\n{\n    return db.Find(clients).Where(s => s.Status == \"Active\");\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>函数命名要见名知义</b></summary>\n\n**Bad:**\n\n```csharp\npublic class Email\n{\n    //...\n\n    public void Handle()\n    {\n        SendMail(this._to, this._subject, this._body);\n    }\n}\n\nvar message = new Email(...);\n// What is this? A handle for the message? Are we writing to a file now?\nmessage.Handle();\n```\n\n**Good:**\n\n```csharp\npublic class Email\n{\n    //...\n\n    public void Send()\n    {\n        SendMail(this._to, this._subject, this._body);\n    }\n}\n\nvar message = new Email(...);\n// Clear and obvious\nmessage.Send();\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>函数应该只包含一层抽象</b></summary>\n\n> 还没完\n\n通常情况下，当你的函数中包含超过一层的抽象表明这个函数做的事情太多了，拆分为多个函数可以提高重用性和更易于测试。\n\n**Bad:**\n\n```csharp\npublic string ParseBetterJSAlternative(string code)\n{\n    var regexes = [\n        // ...\n    ];\n\n    var statements = explode(\" \", code);\n    var tokens = new string[] {};\n    foreach (var regex in regexes)\n    {\n        foreach (var statement in statements)\n        {\n            // ...\n        }\n    }\n\n    var ast = new string[] {};\n    foreach (var token in tokens)\n    {\n        // lex...\n    }\n\n    foreach (var node in ast)\n    {\n        // parse...\n    }\n}\n```\n\n**Bad too:**\n\n我们已经执行了一些操作，但是 `ParseBetterJSAlternative()` 函数依旧很复杂，且不易于测试。\n\n```csharp\npublic string Tokenize(string code)\n{\n    var regexes = new string[]\n    {\n        // ...\n    };\n\n    var statements = explode(\" \", code);\n    var tokens = new string[] {};\n    foreach (var regex in regexes)\n    {\n        foreach (var statement in statements)\n        {\n            tokens[] = /* ... */;\n        }\n    }\n\n    return tokens;\n}\n\npublic string Lexer(string[] tokens)\n{\n    var ast = new string[] {};\n    foreach (var token in tokens)\n    {\n        ast[] = /* ... */;\n    }\n\n    return ast;\n}\n\npublic string ParseBetterJSAlternative(string code)\n{\n    var tokens = Tokenize(code);\n    var ast = Lexer(tokens);\n    foreach (var node in ast)\n    {\n        // parse...\n    }\n}\n```\n\n**Good:**\n\n最好的解决方案是分解 `ParseBetterJSAlternative()` 函数内部的所有依赖性。\n\n```csharp\nclass Tokenizer\n{\n    public string Tokenize(string code)\n    {\n        var regexes = new string[] {\n            // ...\n        };\n\n        var statements = explode(\" \", code);\n        var tokens = new string[] {};\n        foreach (var regex in regexes)\n        {\n            foreach (var statement in statements)\n            {\n                tokens[] = /* ... */;\n            }\n        }\n\n        return tokens;\n    }\n}\n\nclass Lexer\n{\n    public string Lexify(string[] tokens)\n    {\n        var ast = new[] {};\n        foreach (var token in tokens)\n        {\n            ast[] = /* ... */;\n        }\n\n        return ast;\n    }\n}\n\nclass BetterJSAlternative\n{\n    private string _tokenizer;\n    private string _lexer;\n\n    public BetterJSAlternative(Tokenizer tokenizer, Lexer lexer)\n    {\n        _tokenizer = tokenizer;\n        _lexer = lexer;\n    }\n\n    public string Parse(string code)\n    {\n        var tokens = _tokenizer.Tokenize(code);\n        var ast = _lexer.Lexify(tokens);\n        foreach (var node in ast)\n        {\n            // parse...\n        }\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n\n<details>\n  <summary><b>函数调用方和被调用方应该位置相近</b></summary>\n\n如果一个函数调用了其它函数，请保持这些函数顺序位于同一个源代码文件中。理想情况下，让被调用者位于调用者上方。我们倾向于像读报纸一样从上到下来阅读代码。因此，请以这种阅读方式来布局代码。\n\n**Bad:**\n\n```csharp\nclass PerformanceReview\n{\n    private readonly Employee _employee;\n\n    public PerformanceReview(Employee employee)\n    {\n        _employee = employee;\n    }\n\n    private IEnumerable<PeersData> LookupPeers()\n    {\n        return db.lookup(_employee, 'peers');\n    }\n\n    private ManagerData LookupManager()\n    {\n        return db.lookup(_employee, 'manager');\n    }\n\n    private IEnumerable<PeerReviews> GetPeerReviews()\n    {\n        var peers = LookupPeers();\n        // ...\n    }\n\n    public PerfReviewData PerfReview()\n    {\n        GetPeerReviews();\n        GetManagerReview();\n        GetSelfReview();\n    }\n\n    public ManagerData GetManagerReview()\n    {\n        var manager = LookupManager();\n    }\n\n    public EmployeeData GetSelfReview()\n    {\n        // ...\n    }\n}\n\nvar  review = new PerformanceReview(employee);\nreview.PerfReview();\n```\n\n**Good:**\n\n```csharp\nclass PerformanceReview\n{\n    private readonly Employee _employee;\n\n    public PerformanceReview(Employee employee)\n    {\n        _employee = employee;\n    }\n\n    public PerfReviewData PerfReview()\n    {\n        GetPeerReviews();\n        GetManagerReview();\n        GetSelfReview();\n    }\n\n    private IEnumerable<PeerReviews> GetPeerReviews()\n    {\n        var peers = LookupPeers();\n        // ...\n    }\n\n    private IEnumerable<PeersData> LookupPeers()\n    {\n        return db.lookup(_employee, 'peers');\n    }\n\n    private ManagerData GetManagerReview()\n    {\n        var manager = LookupManager();\n        return manager;\n    }\n\n    private ManagerData LookupManager()\n    {\n        return db.lookup(_employee, 'manager');\n    }\n\n    private EmployeeData GetSelfReview()\n    {\n        // ...\n    }\n}\n\nvar review = new PerformanceReview(employee);\nreview.PerfReview();\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>封装条件</b></summary>\n\n**Bad:**\n\n```csharp\nif (article.state == \"published\")\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\nif (article.IsPublished())\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>移除废弃代码</b></summary>\n\n废弃代码和重复代码一样糟糕，毫无疑问不应该让其存在于你的代码库中。如果它不会被调用，那就删除它！如果你仍然需要它的话，它可以安全的存在于你的版本控制中。\n\n**Bad:**\n\n```csharp\npublic void OldRequestModule(string url)\n{\n    // ...\n}\n\npublic void NewRequestModule(string url)\n{\n    // ...\n}\n\nvar request = NewRequestModule(requestUrl);\nInventoryTracker(\"apples\", request, \"www.inventory-awesome.io\");\n```\n\n**Good:**\n\n```csharp\npublic void RequestModule(string url)\n{\n    // ...\n}\n\nvar request = RequestModule(requestUrl);\nInventoryTracker(\"apples\", request, \"www.inventory-awesome.io\");\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 对象和数据结构\n\n\n<details>\n  <summary><b>使用 getters 和 setters</b></summary>\n\n在 C# / VB.NET 中，你可以为方法添加 `public`, `protected` 和 `private` 关键字。通过使用这些关键字，你可以控制对象的一些成员的访问权限。\n\n- 当你尝试通过一个对象属性来进行更多的操作，你不得不在你的代码中查找和修改它们的访问权限。\n- 通过使用 `set` 关键字可以让属性验证变得更简单。\n- 封装内部的展现形式。\n- 当进行 getting 和 setting 操作时可以更容易的添加日志和异常处理。\n- 基础基类后，你可以重写默认方法。\n- 如果是从服务器获取一个对象，你可以使用懒加载来处理对象的属性。\n\n此外，在面向对象设计原则中，这也是开闭原则的一部分。\n\n**Bad:**\n\n```csharp\nclass BankAccount\n{\n    public double Balance = 1000;\n}\n\nvar bankAccount = new BankAccount();\n\n// Fake buy shoes...\nbankAccount.Balance -= 100;\n```\n\n**Good:**\n\n```csharp\nclass BankAccount\n{\n    private double _balance = 0.0D;\n\n    pubic double Balance {\n        get {\n            return _balance;\n        }\n    }\n\n    public BankAccount(balance = 1000)\n    {\n       _balance = balance;\n    }\n\n    public void WithdrawBalance(int amount)\n    {\n        if (amount > _balance)\n        {\n            throw new Exception('Amount greater than available balance.');\n        }\n\n        _balance -= amount;\n    }\n\n    public void DepositBalance(int amount)\n    {\n        _balance += amount;\n    }\n}\n\nvar bankAccount = new BankAccount();\n\n// Buy shoes...\nbankAccount.WithdrawBalance(price);\n\n// Get balance\nbalance = bankAccount.Balance;\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>让对象具有私有/受保护的成员</b></summary>\n\n**Bad:**\n\n```csharp\nclass Employee\n{\n    public string Name { get; set; }\n\n    public Employee(name)\n    {\n        Name = name;\n    }\n}\n\nvar employee = new Employee('John Doe');\nConsole.WriteLine(employee.Name) // Employee name: John Doe\n```\n\n**Good:**\n\n```csharp\nclass Employee\n{\n    public string Name { get; }\n\n    public Employee(string name)\n    {\n        Name = name;\n    }\n}\n\nvar employee = new Employee('John Doe');\nConsole.WriteLine(employee.GetName());// Employee name: John Doe\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n## 类\n\n<details>\n  <summary><b>使用链式方法</b></summary>\n\n在一些类库中，这种模式是很有用且很常见的操作。它可以让你的代码以一种表达式的方式来呈现，更加简洁。因此，使用链式方法可以让你的代码看上去更加简洁。\n\n**Good:**\n\n```csharp\npublic static class ListExtensions\n{\n    public static List<T> FluentAdd<T>(this List<T> list, T item)\n    {\n        list.Add(item);\n        return list;\n    }\n\n    public static List<T> FluentClear<T>(this List<T> list)\n    {\n        list.Clear();\n        return list;\n    }\n\n    public static List<T> FluentForEach<T>(this List<T> list, Action<T> action)\n    {\n        list.ForEach(action);\n        return list;\n    }\n\n    public static List<T> FluentInsert<T>(this List<T> list, int index, T item)\n    {\n        list.Insert(index, item);\n        return list;\n    }\n\n    public static List<T> FluentRemoveAt<T>(this List<T> list, int index)\n    {\n        list.RemoveAt(index);\n        return list;\n    }\n\n    public static List<T> FluentReverse<T>(this List<T> list)\n    {\n        list.Reverse();\n        return list;\n    }\n}\n\ninternal static void ListFluentExtensions()\n{\n    var list = new List<int>() { 1, 2, 3, 4, 5 }\n        .FluentAdd(1)\n        .FluentInsert(0, 0)\n        .FluentRemoveAt(1)\n        .FluentReverse()\n        .FluentForEach(value => value.WriteLine())\n        .FluentClear();\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>组合优于继承</b></summary>\n\n正如由 Gang of Four 编写的著作 [_Design Patterns_](https://en.wikipedia.org/wiki/Design_Patterns) 里面所述。如果可以选择的话，你应该倾向于使用组合而不是继承。这里面有很多不错的原因来论述使用继承和组合。\n\n关于这一论点的主要观点是如果你本能地尝试使用继承，那么考虑一下组合是否能更好的解决你的问题，在某些情况下，它确实可以。\n\n你可能接着会疑惑，\"我应该什么时候使用继承？\" 这取决你你怎么解决问题，这里有一个不错的列表来指导你在什么情况下使用继承更有意义，而不是组合。\n\n1. 你的继承是为了表达一种 \"是 A\" 的关系而不是 \"有 A\" 的关系 (人类->动物 vs. 用户->用户详情).\n2. 你可以从基类重用代码 (人类像所有动物一样可以移动)。\n3. 您希望通过更改基类对派生类进行全局更改 (改变所有动物移动时的热量消耗。)\n\n**Bad:**\n\n```csharp\nclass Employee\n{\n    private string Name { get; set; }\n    private string Email { get; set; }\n\n    public Employee(string name, string email)\n    {\n        Name = name;\n        Email = email;\n    }\n\n    // ...\n}\n\n// Bad because Employees \"have\" tax data.\n// EmployeeTaxData is not a type of Employee\n\nclass EmployeeTaxData : Employee\n{\n    private string Name { get; }\n    private string Email { get; }\n\n    public EmployeeTaxData(string name, string email, string ssn, string salary)\n    {\n         // ...\n    }\n\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\nclass EmployeeTaxData\n{\n    public string Ssn { get; }\n    public string Salary { get; }\n\n    public EmployeeTaxData(string ssn, string salary)\n    {\n        Ssn = ssn;\n        Salary = salary;\n    }\n\n    // ...\n}\n\nclass Employee\n{\n    public string Name { get; }\n    public string Email { get; }\n    public EmployeeTaxData TaxData { get; }\n\n    public Employee(string name, string email)\n    {\n        Name = name;\n        Email = email;\n    }\n\n    public void SetTax(string ssn, double salary)\n    {\n        TaxData = new EmployeeTaxData(ssn, salary);\n    }\n\n    // ...\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## SOLID\n\n\n<details>\n  <summary><b>什么是 SOLID?</b></summary>\n\n**SOLID** 是 Michael Feathers 为  Robert Martin 命名的前五个原则引入的首字母简称。它指导者面向对象编程和设计的五个基本原则。\n\n- [S: 单一职责原则 (SRP)](#single-responsibility-principle-srp)\n- [O: 开/闭原则 (OCP)](#openclosed-principle-ocp)\n- [L: 里氏替换原则 (LSP)](#liskov-substitution-principle-lsp)\n- [I: 接口隔离原则 (ISP)](#interface-segregation-principle-isp)\n- [D: 依赖倒置原则 (DIP)](#dependency-inversion-principle-dip)\n\n</details>\n\n\n<details>\n  <summary><b>单一职责原则 (SRP)</b></summary>\n\n如代码整洁之道中所述的那样，\"类更改的原因永远不应该超过一个\"。一个功能繁多的类似乎很有诱惑力，像你登机时只能携带一个手提箱，但问题在于你的类不会具有凝聚力，它会被赋予许多可以改变的理由。尽量减少更改类所需要的时间很重要。\n\n这很重要，因为如果一个类中包含太多功能，并且更改了部分，这会导致很难理解这些更改会怎样影响到代码库中其它的依赖项。\n\n**Bad:**\n\n```csharp\nclass UserSettings\n{\n    private User User;\n\n    public UserSettings(User user)\n    {\n        User = user;\n    }\n\n    public void ChangeSettings(Settings settings)\n    {\n        if (verifyCredentials())\n        {\n            // ...\n        }\n    }\n\n    private bool VerifyCredentials()\n    {\n        // ...\n    }\n}\n```\n\n**Good:**\n\n```csharp\nclass UserAuth\n{\n    private User User;\n\n    public UserAuth(User user)\n    {\n        User = user;\n    }\n\n    public bool VerifyCredentials()\n    {\n        // ...\n    }\n}\n\nclass UserSettings\n{\n    private User User;\n    private UserAuth Auth;\n\n    public UserSettings(User user)\n    {\n        User = user;\n        Auth = new UserAuth(user);\n    }\n\n    public void ChangeSettings(Settings settings)\n    {\n        if (Auth.VerifyCredentials())\n        {\n            // ...\n        }\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>开/闭原则 (OCP)</b></summary>\n\n正如 Bertrand Meyer 所述的那样，\"软件实体 (类，模块，函数等) 应该对扩展开放，对修改关闭。\" 这想表达什么呢？这个原则最基本的要求是你应该允许用户在不更改现有代码的前提下可以添加新功能。\n\n**Bad:**\n\n```csharp\nabstract class AdapterBase\n{\n    protected string Name;\n\n    public string GetName()\n    {\n        return Name;\n    }\n}\n\nclass AjaxAdapter : AdapterBase\n{\n    public AjaxAdapter()\n    {\n        Name = \"ajaxAdapter\";\n    }\n}\n\nclass NodeAdapter : AdapterBase\n{\n    public NodeAdapter()\n    {\n        Name = \"nodeAdapter\";\n    }\n}\n\nclass HttpRequester : AdapterBase\n{\n    private readonly AdapterBase Adapter;\n\n    public HttpRequester(AdapterBase adapter)\n    {\n        Adapter = adapter;\n    }\n\n    public bool Fetch(string url)\n    {\n        var adapterName = Adapter.GetName();\n\n        if (adapterName == \"ajaxAdapter\")\n        {\n            return MakeAjaxCall(url);\n        }\n        else if (adapterName == \"httpNodeAdapter\")\n        {\n            return MakeHttpCall(url);\n        }\n    }\n\n    private bool MakeAjaxCall(string url)\n    {\n        // request and return promise\n    }\n\n    private bool MakeHttpCall(string url)\n    {\n        // request and return promise\n    }\n}\n```\n\n**Good:**\n\n```csharp\ninterface IAdapter\n{\n    bool Request(string url);\n}\n\nclass AjaxAdapter : IAdapter\n{\n    public bool Request(string url)\n    {\n        // request and return promise\n    }\n}\n\nclass NodeAdapter : IAdapter\n{\n    public bool Request(string url)\n    {\n        // request and return promise\n    }\n}\n\nclass HttpRequester\n{\n    private readonly IAdapter Adapter;\n\n    public HttpRequester(IAdapter adapter)\n    {\n        Adapter = adapter;\n    }\n\n    public bool Fetch(string url)\n    {\n        return Adapter.Request(url);\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>里氏替换原则 (LSP)</b></summary>\n\n对于一个很简单的概念来说，这是很抽象的。它的准确表述是 \"如果 S 是 T 的子类，那么类型 T 的对象可以转化为类型 S 的对象，即在无需修改程序（正确性，任务执行等）的情况下 在类型为 S 的对象可以替换类型为 T 的对象。\" 这是一个相对可怕的定义。\n\n对这一原则最好的解释是如果你有一个父类和一个子类，那么基类和子类可以相互使用，而不会得到错误答案，这可能仍然令人困惑。在数学上，正方形是一个矩形，但是使用 \"is-a\" 关系通过继承对它建模，你很快就会陷入麻烦。\n\n**Bad:**\n\n```csharp\nclass Rectangle\n{\n    protected double Width = 0;\n    protected double Height = 0;\n\n    public Drawable Render(double area)\n    {\n        // ...\n    }\n\n    public void SetWidth(double width)\n    {\n        Width = width;\n    }\n\n    public void SetHeight(double height)\n    {\n        Height = height;\n    }\n\n    public double GetArea()\n    {\n        return Width * Height;\n    }\n}\n\nclass Square : Rectangle\n{\n    public double SetWidth(double width)\n    {\n        Width = Height = width;\n    }\n\n    public double SetHeight(double height)\n    {\n        Width = Height = height;\n    }\n}\n\nDrawable RenderLargeRectangles(Rectangle rectangles)\n{\n    foreach (rectangle in rectangles)\n    {\n        rectangle.SetWidth(4);\n        rectangle.SetHeight(5);\n        var area = rectangle.GetArea(); // BAD: Will return 25 for Square. Should be 20.\n        rectangle.Render(area);\n    }\n}\n\nvar rectangles = new[] { new Rectangle(), new Rectangle(), new Square() };\nRenderLargeRectangles(rectangles);\n```\n\n**Good:**\n\n```csharp\nabstract class ShapeBase\n{\n    protected double Width = 0;\n    protected double Height = 0;\n\n    abstract public double GetArea();\n\n    public Drawable Render(double area)\n    {\n        // ...\n    }\n}\n\nclass Rectangle : ShapeBase\n{\n    public void SetWidth(double width)\n    {\n        Width = width;\n    }\n\n    public void SetHeight(double height)\n    {\n        Height = height;\n    }\n\n    public double GetArea()\n    {\n        return Width * Height;\n    }\n}\n\nclass Square : ShapeBase\n{\n    private double Length = 0;\n\n    public double SetLength(double length)\n    {\n        Length = length;\n    }\n\n    public double GetArea()\n    {\n        return Math.Pow(Length, 2);\n    }\n}\n\nDrawable RenderLargeRectangles(Rectangle rectangles)\n{\n    foreach (rectangle in rectangles)\n    {\n        if (rectangle is Square)\n        {\n            rectangle.SetLength(5);\n        }\n        else if (rectangle is Rectangle)\n        {\n            rectangle.SetWidth(4);\n            rectangle.SetHeight(5);\n        }\n\n        var area = rectangle.GetArea();\n        rectangle.Render(area);\n    }\n}\n\nvar shapes = new[] { new Rectangle(), new Rectangle(), new Square() };\nRenderLargeRectangles(shapes);\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>接口隔离原则 (ISP)</b></summary>\n\nISP 指出 \"不应该强迫客户端依赖于它不使用的接口。\"\n\n一个很好的例子可以很好地证明这一点。比如需要大量的设置对象，不需要客户端创建很多的设置项是正确的，因为大多数情况下，它们并不需要所有的设置项，使它们作为可选项有助于防止出现 \"胖接口\"。\n\n**Bad:**\n\n```csharp\npublic interface IEmployee\n{\n    void Work();\n    void Eat();\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n\n    public void Eat()\n    {\n        // ...... eating in lunch break\n    }\n}\n\npublic class Robot : IEmployee\n{\n    public void Work()\n    {\n        //.... working much more\n    }\n\n    public void Eat()\n    {\n        //.... robot can't eat, but it must implement this method\n    }\n}\n```\n\n**Good:**\n\nNot every worker is an employee, but every employee is an worker.\n\n```csharp\npublic interface IWorkable\n{\n    void Work();\n}\n\npublic interface IFeedable\n{\n    void Eat();\n}\n\npublic interface IEmployee : IFeedable, IWorkable\n{\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n\n    public void Eat()\n    {\n        //.... eating in lunch break\n    }\n}\n\n// robot can only work\npublic class Robot : IWorkable\n{\n    public void Work()\n    {\n        // ....working\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>依赖倒置原则 (DIP)</b></summary>\n\n这一原则指出两个基本点：\n\n1. 高级别模块不应该依赖于低级别模块，它们都应该依赖于抽象层。\n2. 抽象不应该依赖于细节，细节应该依赖于抽象。\n\n这一点最初很难理解。但如果你已经使用 .NET/.NET Core framework，你应该已经看过 [Dependency Injection](https://martinfowler.com/articles/injection.html) (DI) 对这一原则的实现。虽然它们不是相同的概念，但 DIP 使高级模块无法了解低级模块的详细信息，也无法设置。这可以通过 DI 来实现，这样做的最大好处是减少了模块间的耦合，耦合是一种非常非常糟糕的开发模式，它会导致代码难以重构。\n\n**Bad:**\n\n```csharp\npublic abstract class EmployeeBase\n{\n    protected virtual void Work()\n    {\n        // ....working\n    }\n}\n\npublic class Human : EmployeeBase\n{\n    public override void Work()\n    {\n        //.... working much more\n    }\n}\n\npublic class Robot : EmployeeBase\n{\n    public override void Work()\n    {\n        //.... working much, much more\n    }\n}\n\npublic class Manager\n{\n    private readonly Robot _robot;\n    private readonly Human _human;\n\n    public Manager(Robot robot, Human human)\n    {\n        _robot = robot;\n        _human = human;\n    }\n\n    public void Manage()\n    {\n        _robot.Work();\n        _human.Work();\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic interface IEmployee\n{\n    void Work();\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n}\n\npublic class Robot : IEmployee\n{\n    public void Work()\n    {\n        //.... working much more\n    }\n}\n\npublic class Manager\n{\n    private readonly IEnumerable<IEmployee> _employees;\n\n    public Manager(IEnumerable<IEmployee> employees)\n    {\n        _employees = employees;\n    }\n\n    public void Manage()\n    {\n        foreach (var employee in _employees)\n        {\n            _employee.Work();\n        }\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>不要重复你自己 (DRY)</b></summary>\n\n尝试了解  [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) 原则\n\n尽你所能去避免重复的代码，重复代码不好，因为这意味着如果你修改某些逻辑，那么你需要在很多地方修改这些逻辑。\n\n想象一下，如果你经营一家餐馆，并跟踪你的库存：所有的西红柿，洋葱，大蒜，香料等。如果您有多份列表，当你使用了菜与西红柿，你更新了这份列表，那么其它列表都需要更新。如果您只有一份列表，则只需要更新一个位置即可！\n\n通常，你有重复的代码是由于你有两个或者更多略有差异的地方，它们有很多共同点，但它们的不同点迫使你不得不视图两个或多个单独的函数，这些函数也会执行许多相同的操作。删除重复的代码意味着创建一个抽象，只需一个函数/模块/类即可处理这组不同的东西。\n\n正确抽象至关重要，这就是为什么你应该遵循 [Classes]（#classes） 一节中阐述的 SOLID 原则的原因。错误的抽象可能比重复的代码更糟糕，所以要小心！话虽如此，如果你能做出一个良好的抽象，做到这一点！不要重复自己，否则你当你想做一处修改的时候会发现自己需要更新多个地方。\n\n**Bad:**\n\n```csharp\npublic List<EmployeeData> ShowDeveloperList(Developers developers)\n{\n    foreach (var developers in developer)\n    {\n        var expectedSalary = developer.CalculateExpectedSalary();\n        var experience = developer.GetExperience();\n        var githubLink = developer.GetGithubLink();\n        var data = new[] {\n            expectedSalary,\n            experience,\n            githubLink\n        };\n\n        Render(data);\n    }\n}\n\npublic List<ManagerData> ShowManagerList(Manager managers)\n{\n    foreach (var manager in managers)\n    {\n        var expectedSalary = manager.CalculateExpectedSalary();\n        var experience = manager.GetExperience();\n        var githubLink = manager.GetGithubLink();\n        var data =\n        new[] {\n            expectedSalary,\n            experience,\n            githubLink\n        };\n\n        render(data);\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic List<EmployeeData> ShowList(Employee employees)\n{\n    foreach (var employee in employees)\n    {\n        var expectedSalary = employees.CalculateExpectedSalary();\n        var experience = employees.GetExperience();\n        var githubLink = employees.GetGithubLink();\n        var data =\n        new[] {\n            expectedSalary,\n            experience,\n            githubLink\n        };\n\n        render(data);\n    }\n}\n```\n\n**Very good:**\n\nIt is better to use a compact version of the code.\n\n```csharp\npublic List<EmployeeData> ShowList(Employee employees)\n{\n    foreach (var employee in employees)\n    {\n        render(new[] {\n            employee.CalculateExpectedSalary(),\n            employee.GetExperience(),\n            employee.GetGithubLink()\n        });\n    }\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n</details>\n\n## 测试\n\n<details>\n  <summary><b>测试的基本概念</b></summary>\n\n测试比开发更重要，如果你没有测试或者测试量不够，那么每次发布的时候，你不能确保你没有引入新的 BUG，花费的金额数量取决于你的团队，但拥有 100% 的覆盖率（所有条件和分支）是你实现非常高的可信度和让开发人员安心的方式。这意味着除了拥有一个优秀的测试框架外，你也需要使用 [良好的覆盖工具](https://docs.microsoft.com/en-us/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested).\n\n没有理由不写测试，这里有 [大量的优秀 .NET 测试框架](https://github.com/thangchung/awesome-dotnet-core#testing)，选择一款你所在团队喜欢的框架。当你找到一款适合你团队使用的的测试框架时，其目的是始终为你介绍的每个新功能/模块编写测试。如果你的首选方法是测试驱动开发 （TDD），那很好，但主要目的就是确保在启动任何功能或重构现有功能之前达到覆盖目标。\n\n</details>\n\n<details>\n  <summary><b>每个测试的单一概念</b></summary>\n\n确保你的测试以点为中心，而不是杂乱（不相关）内容，强制使用 [AAA 模式](http://wiki.c2.com/?ArrangeActAssert) 可以然你的代码更加整洁和易读。\n\n**Bad:**\n\n```csharp\n\npublic class MakeDotNetGreatAgainTests\n{\n    [Fact]\n    public void HandleDateBoundaries()\n    {\n        var date = new MyDateTime(\"1/1/2015\");\n        date.AddDays(30);\n        Assert.Equal(\"1/31/2015\", date);\n\n        date = new MyDateTime(\"2/1/2016\");\n        date.AddDays(28);\n        Assert.Equal(\"02/29/2016\", date);\n\n        date = new MyDateTime(\"2/1/2015\");\n        date.AddDays(28);\n        Assert.Equal(\"03/01/2015\", date);\n    }\n}\n\n```\n\n**Good:**\n\n```csharp\n\npublic class MakeDotNetGreatAgainTests\n{\n    [Fact]\n    public void Handle30DayMonths()\n    {\n        // Arrange\n        var date = new MyDateTime(\"1/1/2015\");\n\n        // Act\n        date.AddDays(30);\n\n        // Assert\n        Assert.Equal(\"1/31/2015\", date);\n    }\n\n    [Fact]\n    public void HandleLeapYear()\n    {\n        // Arrange\n        var date = new MyDateTime(\"2/1/2016\");\n\n        // Act\n        date.AddDays(28);\n\n        // Assert\n        Assert.Equal(\"02/29/2016\", date);\n    }\n\n    [Fact]\n    public void HandleNonLeapYear()\n    {\n        // Arrange\n        var date = new MyDateTime(\"2/1/2015\");\n\n        // Act\n        date.AddDays(28);\n\n        // Assert\n        Assert.Equal(\"03/01/2015\", date);\n    }\n}\n\n```\n\n> Soure https://www.codingblocks.net/podcast/how-to-write-amazing-unit-tests\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 并发\n\n<details>\n  <summary><b>使用 Async/Await</b></summary>\n\n**异步编程指南摘要**\n\n| Name              | Description                                       | Exceptions                      |\n| ----------------- | ------------------------------------------------- | ------------------------------- |\n| Avoid async void  | Prefer async Task methods over async void methods | Event handlers                  |\n| Async all the way | Don't mix blocking and async code                 | Console main method (C# <= 7.0) |\n| Configure context | Use `ConfigureAwait(false)` when you can          | Methods that require con­text   |\n\n**异步方式处理**\n\n| To Do This ...                           | Instead of This ...        | Use This             |\n| ---------------------------------------- | -------------------------- | -------------------- |\n| Retrieve the result of a background task | `Task.Wait or Task.Result` | `await`              |\n| Wait for any task to complete            | `Task.WaitAny`             | `await Task.WhenAny` |\n| Retrieve the results of multiple tasks   | `Task.WaitAll`             | `await Task.WhenAll` |\n| Wait a period of time                    | `Thread.Sleep`             | `await Task.Delay`   |\n\n**最佳实践**\n\nasync/await 最适用于 IO 型任务（网络通信，数据库通信，http 请求等），但它不适用于计算型任务（遍历巨型列表，渲染处理图片等）。因为它会将保留线程释放到线程池，可用的 CPU/内核 将不涉及处理这些任务。因此，我们应该避免使用 Async/Await 进行计算型任务。\n\n对于处理计算型任务，倾向于结合 `TaskCreationOptions` 和 `LongRunning` 来使用 `Task.Factory.CreateNew`，它将启动一个新的后台线程来处理繁重的计算型任务，而不会将其释放回线程池，直到任务完成。\n\n**了解你的工具**\n\n关于 async 和 await 有太多地方需要学习， 有些困惑是很自然的。以下是一些常见问题的快速解决指南。\n\n**常见异步问题的解决方法**\n\n| Problem                                         | Solution                                                                          |\n| ----------------------------------------------- | --------------------------------------------------------------------------------- |\n| Create a task to execute code                   | `Task.Run` or `TaskFactory.StartNew` (not the `Task` constructor or `Task.Start`) |\n| Create a task wrapper for an operation or event | `TaskFactory.FromAsync` or `TaskCompletionSource<T>`                              |\n| Support cancellation                            | `CancellationTokenSource` and `CancellationToken`                                 |\n| Report progress                                 | `IProgress<T>` and `Progress<T>`                                                  |\n| Handle streams of data                          | TPL Dataflow or Reactive Extensions                                               |\n| Synchronize access to a shared resource         | `SemaphoreSlim`                                                                   |\n| Asynchronously initialize a resource            | `AsyncLazy<T>`                                                                    |\n| Async-ready producer/consumer structures        | TPL Dataflow or `AsyncCollection<T>`                                              |\n\n阅读 [Task-based Asynchronous Pattern (TAP) document](http://www.microsoft.com/download/en/details.aspx?id=19957)。它编写得非常好，包括有关 API 设计和正确使用异步/等待（包括取消和进度报告）的指导。\n\n应该使用新的 await-friendly 方法来替代旧的方法。如果你新的异步代码中有旧的示例，这说明你写错了。\n\n| Old                | New                                  | Description                                                   |\n| ------------------ | ------------------------------------ | ------------------------------------------------------------- |\n| `task.Wait`        | `await task`                         | Wait/await for a task to complete                             |\n| `task.Result`      | `await task`                         | Get the result of a completed task                            |\n| `Task.WaitAny`     | `await Task.WhenAny`                 | Wait/await for one of a collection of tasks to complete       |\n| `Task.WaitAll`     | `await Task.WhenAll`                 | Wait/await for every one of a collection of tasks to complete |\n| `Thread.Sleep`     | `await Task.Delay`                   | Wait/await for a period of time                               |\n| `Task` constructor | `Task.Run` or `TaskFactory.StartNew` | Create a code-based task                                      |\n\n> Source https://gist.github.com/jonlabelle/841146854b23b305b50fa5542f84b20c\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 异常处理\n\n<details>\n  <summary><b>异常处理的基本概念</b></summary>\n\n抛出异常是一件好事！这意味了程序在运行时成功识别程序中出现的问题，通过停止当前堆栈上的函数执行，终止进程 (在 .NET/.NET Core 里)，并在控制台中通过堆栈跟踪来通知你。\n\n</details>\n\n<details>\n  <summary><b>在 catch 块中不要使用 'throw ex'</b></summary>\n\n如果你在捕获一个异常之后需要重新抛出一个异常，仅仅使用 'throw' ，你将会保存堆栈跟踪，但在坏的情况下，你将丢失堆栈跟踪。\n\n**Bad:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n    // Any action something like roll-back or logging etc.\n    throw ex;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n    // Any action something like roll-back or logging etc.\n    throw;\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>不要忽略捕获的异常</b></summary>\n\n对捕获到的错误置之不理并不能解决问题，抛出异常也好不了哪儿去，因为它们常常无法准确在控制台中显示出来。如果将一些代码放到 `try/catch` 中就意味着你认为这里可能会发生异常。因此你应该制定计划，创建代码分支，为异常发生做准备。\n\n**Bad:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception ex)\n{\n    // silent exception\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    NotifyUserOfError(error);\n\n    // Another option\n    ReportErrorToService(error);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n\n<details>\n  <summary><b>使用多个 catch 块而不是 if 条件</b></summary>\n\n如果你需要对不同类型的异常做不同操作，你最好使用多个 catch 块来处理它们。\n\n**Bad:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n\n    if (ex is TaskCanceledException)\n    {\n        // Take action for TaskCanceledException\n    }\n    else if (ex is TaskSchedulerException)\n    {\n        // Take action for TaskSchedulerException\n    }\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (TaskCanceledException ex)\n{\n    // Take action for TaskCanceledException\n}\ncatch (TaskSchedulerException ex)\n{\n    // Take action for TaskSchedulerException\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>在重新引发异常时保留异常堆栈跟踪</b></summary>\n\nC# 允许使用 \"throw\" 关键字在 catch 块中重新引发异常。使用 \"throw e;\" 抛出捕获的异常是一种不好的做法。此语句会重置堆栈跟踪。而使用 \"throw;\"，这将保持堆栈跟踪，并提供有关异常的更深入的信息。另一个选项是使用自定义异常。只需实例化新异常，并将其内部异常属性设置为捕获的异常，并引发 `new CustomException(\"some info\", e);` 。向异常添加信息是一种好的做法，因为它有助于调试。但是，如果目标是记录异常，则使用 \"throw;\" 将降级传递给调用方。\n\n**Bad:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception ex)\n{\n    logger.LogInfo(ex);\n    throw ex;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    logger.LogInfo(error);\n    throw;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    logger.LogInfo(error);\n    throw new CustomException(error);\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 格式化\n\n<details>\n  <summary><b>使用 <i>.editorconfig</i> 文件</b></summary>\n\n**Bad:**\n\n一个项目中有一些代码格式化文件，缩进样式在项目中被 `space` 和 `tab` 混淆。\n\n**Good:**\n\n在代码库中使用 `.editorconfig` 文件来定义和维护一致的代码样式。\n\n```csharp\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n# C# files\n[*.cs]\nindent_size = 4\n# New line preferences\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_before_else = true\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_within_query_expression_clauses = true\n\n# Code files\n[*.{cs,csx,vb,vbx}]\nindent_size = 4\n\n# Indentation preferences\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_switch_labels = true\ncsharp_indent_labels = one_less_than_current\n\n# avoid this. unless absolutely necessary\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_event = false:suggestion\n\n# only use var when it's obvious what the variable type is\n# csharp_style_var_for_built_in_types = false:none\n# csharp_style_var_when_type_is_apparent = false:none\n# csharp_style_var_elsewhere = false:suggestion\n\n# use language keywords instead of BCL types\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\n# name all constant fields using PascalCase\ndotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.constant_fields_should_be_pascal_case.symbols  = constant_fields\ndotnet_naming_rule.constant_fields_should_be_pascal_case.style    = pascal_case_style\n\ndotnet_naming_symbols.constant_fields.applicable_kinds   = field\ndotnet_naming_symbols.constant_fields.required_modifiers = const\n\ndotnet_naming_style.pascal_case_style.capitalization = pascal_case\n\n# static fields should have s_ prefix\ndotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion\ndotnet_naming_rule.static_fields_should_have_prefix.symbols  = static_fields\ndotnet_naming_rule.static_fields_should_have_prefix.style    = static_prefix_style\n\ndotnet_naming_symbols.static_fields.applicable_kinds   = field\ndotnet_naming_symbols.static_fields.required_modifiers = static\n\ndotnet_naming_style.static_prefix_style.required_prefix = s_\ndotnet_naming_style.static_prefix_style.capitalization = camel_case\n\n# internal and private fields should be _camelCase\ndotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion\ndotnet_naming_rule.camel_case_for_private_internal_fields.symbols  = private_internal_fields\ndotnet_naming_rule.camel_case_for_private_internal_fields.style    = camel_case_underscore_style\n\ndotnet_naming_symbols.private_internal_fields.applicable_kinds = field\ndotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal\n\ndotnet_naming_style.camel_case_underscore_style.required_prefix = _\ndotnet_naming_style.camel_case_underscore_style.capitalization = camel_case\n\n# Code style defaults\ndotnet_sort_system_directives_first = true\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = false\n\n# Expression-level preferences\ndotnet_style_object_initializer = true:suggestion\ndotnet_style_collection_initializer = true:suggestion\ndotnet_style_explicit_tuple_names = true:suggestion\ndotnet_style_coalesce_expression = true:suggestion\ndotnet_style_null_propagation = true:suggestion\n\n# Expression-bodied members\ncsharp_style_expression_bodied_methods = false:none\ncsharp_style_expression_bodied_constructors = false:none\ncsharp_style_expression_bodied_operators = false:none\ncsharp_style_expression_bodied_properties = true:none\ncsharp_style_expression_bodied_indexers = true:none\ncsharp_style_expression_bodied_accessors = true:none\n\n# Pattern matching\ncsharp_style_pattern_matching_over_is_with_cast_check = true:suggestion\ncsharp_style_pattern_matching_over_as_with_null_check = true:suggestion\ncsharp_style_inlined_variable_declaration = true:suggestion\n\n# Null checking preferences\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_conditional_delegate_call = true:suggestion\n\n# Space preferences\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = do_not_ignore\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n\n[*.{asm,inc}]\nindent_size = 8\n\n# Xml project files\n[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]\nindent_size = 2\n\n# Xml config files\n[*.{props,targets,config,nuspec}]\nindent_size = 2\n\n[CMakeLists.txt]\nindent_size = 2\n\n[*.cmd]\nindent_size = 2\n\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n## 注释\n\n<details>\n  <summary><b>避免位置标记</b></summary>\n\n它们通常只会增加噪音。让函数和变量名称以及适当的缩进和格式为代码提供可视化结构。\n\n**Bad:**\n\n```csharp\n////////////////////////////////////////////////////////////////////////////////\n// Scope Model Instantiation\n////////////////////////////////////////////////////////////////////////////////\nvar model = new[]\n{\n    menu: 'foo',\n    nav: 'bar'\n};\n\n////////////////////////////////////////////////////////////////////////////////\n// Action setup\n////////////////////////////////////////////////////////////////////////////////\nvoid Actions()\n{\n    // ...\n};\n```\n\n**Bad:**\n\n```csharp\n\n#region Scope Model Instantiation\n\nvar model = {\n    menu: 'foo',\n    nav: 'bar'\n};\n\n#endregion\n\n#region Action setup\n\nvoid Actions() {\n    // ...\n};\n\n#endregion\n```\n\n**Good:**\n\n```csharp\nvar model = new[]\n{\n    menu: 'foo',\n    nav: 'bar'\n};\n\nvoid Actions()\n{\n    // ...\n};\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>不要在代码库中留下注释代码</b></summary>\n\n版本控制存在是有原因的。只应该在历史记录中保留旧代码。\n\n**Bad:**\n\n```csharp\ndoStuff();\n// doOtherStuff();\n// doSomeMoreStuff();\n// doSoMuchStuff();\n```\n\n**Good:**\n\n```csharp\ndoStuff();\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>不要有日志注释</b></summary>\n\n记住，使用版本控制！不需要废弃代码、注释代码，尤其是日志注释。使用 \"git log\" 获取历史记录！\n\n**Bad:**\n\n```csharp\n/**\n * 2018-12-20: Removed monads, didn't understand them (RM)\n * 2017-10-01: Improved using special monads (JP)\n * 2016-02-03: Removed type-checking (LI)\n * 2015-03-14: Added combine with type-checking (JR)\n */\npublic int Combine(int a,int b)\n{\n    return a + b;\n}\n```\n\n**Good:**\n\n```csharp\npublic int Combine(int a,int b)\n{\n    return a + b;\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n<details>\n  <summary><b>只应该在业务逻辑较为复杂的时候才应该添加注释</b></summary>\n\n注释是解释，不是要求，好的代码 _大部分_ 就是文档本身。\n\n**Bad:**\n\n```csharp\npublic int HashIt(string data)\n{\n    // The hash\n    var hash = 0;\n\n    // Length of string\n    var length = data.length;\n\n    // Loop through every character in data\n    for (var i = 0; i < length; i++)\n    {\n        // Get character code.\n        const char = data.charCodeAt(i);\n        // Make the hash\n        hash = ((hash << 5) - hash) + char;\n        // Convert to 32-bit integer\n        hash &= hash;\n    }\n}\n```\n\n**Better but still Bad:**\n\n```csharp\npublic int HashIt(string data)\n{\n    var hash = 0;\n    var length = data.length;\n    for (var i = 0; i < length; i++)\n    {\n        const char = data.charCodeAt(i);\n        hash = ((hash << 5) - hash) + char;\n\n        // Convert to 32-bit integer\n        hash &= hash;\n    }\n}\n```\n\n如果注释解释了代码正在执行的操作，它可能是一个无用的注释，可以使用一个命名良好的变量或函数来解决。前面的代码中的注释可以替换为名为 \"ConvertTo32bitInt\" 的函数，因此此注释仍然毫无用处。\n\n但是，开发人员选择 djb2 哈希算法而不是 sha-1 或其他哈希函数的代码就很难表达。在这种情况下，可以添加注释。\n\n**Good:**\n\n```csharp\npublic int Hash(string data)\n{\n    var hash = 0;\n    var length = data.length;\n\n    for (var i = 0; i < length; i++)\n    {\n        var character = data[i];\n        // use of djb2 hash algorithm as it has a good compromise\n        // between speed and low collision with a very simple implementation\n        hash = ((hash << 5) - hash) + character;\n\n        hash = ConvertTo32BitInt(hash);\n    }\n    return hash;\n}\n\nprivate int ConvertTo32BitInt(int value)\n{\n    return value & value;\n}\n```\n\n**[⬆ back to top](#目录)**\n\n</details>\n\n# 其它关于代码整洁之道的资源\n\n## 其它代码整洁之道列表\n\n- [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript) - Clean Code concepts adapted for JavaScript\n- [clean-code-php](https://github.com/jupeter/clean-code-php) - Clean Code concepts adapted for PHP\n- [clean-code-ruby](https://github.com/uohzxela/clean-code-ruby) - Clean Code concepts adapted for Ruby\n- [clean-code-python](https://github.com/zedr/clean-code-python) - Clean Code concepts adapted for Python\n- [clean-code-typescript](https://github.com/labs42io/clean-code-typescript) - Clean Code concepts adapted for TypeScript\n- [clean-go-article](https://github.com/Pungyeon/clean-go-article) - Clean Code concepts adapted for Golang and an example how to apply [clean code in Golang](https://github.com/Pungyeon/clean-go)\n\n## 工具\n\n- [codemaid](https://github.com/codecadwallader/codemaid) - open source Visual Studio extension to cleanup and simplify our C#, C++, F#, VB, PHP, PowerShell, JSON, XAML, XML, ASP, HTML, CSS, LESS, SCSS, JavaScript and TypeScript coding\n- [Sharpen](https://github.com/sharpenrocks/Sharpen) - Visual Studio extension that intelligently introduces new C# features into your existing code base\n- [tslint-clean-code](https://github.com/Glavin001/tslint-clean-code) - TSLint rules for enforcing Clean Code\n\n## 表格\n\n- [Clean Code](cheetsheets/Clean-Code-V2.4.pdf) - The summary of [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/dp/0132350882) book\n- [Clean Architecture](cheetsheets/Clean-Architecture-V1.0.pdf) - The summary of [Clean Architecture: A Craftsman's Guide to Software Structure and Design](https://www.amazon.com/dp/0134494164) book\n- [Modern JavaScript Cheatsheet](https://github.com/mbeaudru/modern-js-cheatsheet) - Cheatsheet for the JavaScript knowledge you will frequently encounter in modern projects\n- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org) - Cheatsheet was created to provide a concise collection of high value information on specific application security topics\n\n---\n\n# 贡献者\n\n感谢每位参与 `clean-code-dotnet` 项目贡献的朋友。\n\n<a href=\"https://github.com/thangchung/clean-code-dotnet/graphs/contributors\"><img src=\"https://opencollective.com/cleancodedotnet/contributors.svg?width=890\" title=\"contributors\" alt=\"contributors\" /></a>\n\n# 支持者\n\n热爱我们的工作，帮助我们继续我们的活动？[[成为支持者](https://opencollective.com/cleancodedotnet#backer)]\n\n<a href=\"https://opencollective.com/cleancodedotnet#backers\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/backers.svg?width=890\"></a>\n\n# 赞助商\n\n成为赞助商，并在 Github 上的 README 上获取您的徽标，并链接到您的网站。[[成为赞助商](https://opencollective.com/cleancodedotnet#sponsor)]\n\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/4/avatar.svg\"></a>\n\n# 许可证\n\n[![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/)\n\nTo the extent possible under law, [thangchung](https://github.com/thangchung) has waived all copyright and related or neighboring rights to this work.\n\n"
  },
  {
    "path": "README.md",
    "content": "# Clean Code concepts adapted for .NET/.NET Core\n\nIf you liked `clean-code-dotnet` project or if it helped you, please give a star :star: for this repository. That will not only help strengthen our .NET community but also improve skills about the clean code for .NET developers in around the world. Thank you very much :+1:\n\nCheck out my [blog](https://medium.com/@thangchung) or say hi on [Twitter](https://twitter.com/thangchung)!\n\n# Table of Contents\n\n- [Clean Code concepts adapted for .NET/.NET Core](#clean-code-concepts-adapted-for-netnet-core)\n- [Table of Contents](#table-of-contents)\n- [Introduction](#introduction)\n- [Clean Code .NET](#clean-code-net)\n  - [Naming](#naming)\n  - [Variables](#variables)\n  - [Functions](#functions)\n  - [Objects and Data Structures](#objects-and-data-structures)\n  - [Classes](#classes)\n  - [SOLID](#solid)\n  - [Testing](#testing)\n  - [Concurrency](#concurrency)\n  - [Error Handling](#error-handling)\n  - [Formatting](#formatting)\n  - [Comments](#comments)\n- [Other Clean Code Resources](#other-clean-code-resources)\n  - [Other Clean Code Lists](#other-clean-code-lists)\n  - [Style Guides](#style-guides)\n  - [Tools](#tools)\n  - [Cheatsheets](#cheatsheets)\n- [Contributors](#contributors)\n- [Backers](#backers)\n- [Sponsors](#sponsors)\n- [License](#license)\n\n# Introduction\n\n![Humorous image of software quality estimation as a count of how many expletives you shout when reading code](http://www.osnews.com/images/comics/wtfm.jpg)\n\nSoftware engineering principles, from Robert C. Martin's book [_Clean Code_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882), adapted for .NET/.NET Core. This is not a style guide. It's a guide to producing readable, reusable, and refactorable software in .NET/.NET Core.\n\nNot every principle herein has to be strictly followed, and even fewer will be universally agreed upon. These are guidelines and nothing more, but they are ones codified over many years of collective experience by the authors of _Clean Code_.\n\nInspired from [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript) and [clean-code-php](https://github.com/jupeter/clean-code-php) lists.\n\n# Clean Code .NET\n\n## Naming\n\n<details>\n  <summary><b>Avoid using bad names</b></summary>\nA good name allows the code to be used by many developers. The name should reflect what it does and give context.\n\n**Bad:**\n\n```csharp\nint d;\n```\n\n**Good:**\n\n```csharp\nint daySinceModification;\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid Misleading Names</b></summary>\n\nName the variable to reflect what it is used for.\n\n**Bad:**\n\n```csharp\nvar dataFromDb = db.GetFromService().ToList();\n```\n\n**Good:**\n\n```csharp\nvar listOfEmployee = _employeeService.GetEmployees().ToList();\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid Hungarian notation</b></summary>\n\nHungarian Notation restates the type which is already present in the declaration. This is pointless since modern IDEs will identify the type.\n\n**Bad:**\n\n```csharp\nint iCounter;\nstring strFullName;\nDateTime dModifiedDate;\n```\n\n**Good:**\n\n```csharp\nint counter;\nstring fullName;\nDateTime modifiedDate;\n```\n\nHungarian Notation should also not be used in paramaters.\n\n**Bad:**\n\n```csharp\npublic bool IsShopOpen(string pDay, int pAmount)\n{\n    // some logic\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsShopOpen(string day, int amount)\n{\n    // some logic\n}\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use consistent capitalization</b></summary>\n\nCapitalization tells you a lot about your variables,\nfunctions, etc. These rules are subjective, so your team can choose whatever\nthey want. The point is, no matter what you all choose, just be consistent.\n\n**Bad:**\n\n```csharp\nconst int DAYS_IN_WEEK = 7;\nconst int daysInMonth = 30;\n\nvar songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' };\nvar Artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' };\n\nbool EraseDatabase() {}\nbool Restore_database() {}\n\nclass animal {}\nclass Alpaca {}\n```\n\n**Good:**\n\n```csharp\nconst int DaysInWeek = 7;\nconst int DaysInMonth = 30;\n\nvar songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' };\nvar artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' };\n\nbool EraseDatabase() {}\nbool RestoreDatabase() {}\n\nclass Animal {}\nclass Alpaca {}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use pronounceable names</b></summary>\n\nIt will take time to investigate the meaning of the variables and functions when they are not pronounceable.\n\n**Bad:**\n\n```csharp\npublic class Employee\n{\n    public Datetime sWorkDate { get; set; } // what the heck is this\n    public Datetime modTime { get; set; } // same here\n}\n```\n\n**Good:**\n\n```csharp\npublic class Employee\n{\n    public Datetime StartWorkingDate { get; set; }\n    public Datetime ModificationTime { get; set; }\n}\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use Camelcase notation</b></summary>\n\nUse [Camelcase Notation](https://en.wikipedia.org/wiki/Camel_case) for variable and method paramaters.\n\n**Bad:**\n\n```csharp\nvar employeephone;\n\npublic double CalculateSalary(int workingdays, int workinghours)\n{\n    // some logic\n}\n```\n\n**Good:**\n\n```csharp\nvar employeePhone;\n\npublic double CalculateSalary(int workingDays, int workingHours)\n{\n    // some logic\n}\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use domain name</b></summary>\n\nPeople who read your code are also programmers. Naming things right will help everyone be on the same page. We don't want to take time to explain to everyone what a variable or function is for.\n\n**Good**\n\n```csharp\npublic class SingleObject\n{\n    // create an object of SingleObject\n    private static SingleObject _instance = new SingleObject();\n\n    // make the constructor private so that this class cannot be instantiated\n    private SingleObject() {}\n\n    // get the only object available\n    public static SingleObject GetInstance()\n    {\n        return _instance;\n    }\n\n    public string ShowMessage()\n    {\n        return \"Hello World!\";\n    }\n}\n\npublic static void main(String[] args)\n{\n    // illegal construct\n    // var object = new SingleObject();\n\n    // Get the only object available\n    var singletonObject = SingleObject.GetInstance();\n\n    // show the message\n    singletonObject.ShowMessage();\n}\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n## Variables\n\n<details>\n  <summary><b>Avoid nesting too deeply and return early</b></summary>\n\nToo many if else statements can make the code hard to follow. **Explicit is better than implicit**.\n\n**Bad:**\n\n```csharp\npublic bool IsShopOpen(string day)\n{\n    if (!string.IsNullOrEmpty(day))\n    {\n        day = day.ToLower();\n        if (day == \"friday\")\n        {\n            return true;\n        }\n        else if (day == \"saturday\")\n        {\n            return true;\n        }\n        else if (day == \"sunday\")\n        {\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n    }\n    else\n    {\n        return false;\n    }\n\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsShopOpen(string day)\n{\n    if (string.IsNullOrEmpty(day))\n    {\n        return false;\n    }\n\n    string[] openingDays = [\"friday\", \"saturday\", \"sunday\"];\n    return openingDays.Any(d => d == day.ToLower());\n}\n```\n\n**Bad:**\n\n```csharp\npublic long Fibonacci(int n)\n{\n    if (n < 50)\n    {\n        if (n != 0)\n        {\n            if (n != 1)\n            {\n                return Fibonacci(n - 1) + Fibonacci(n - 2);\n            }\n            else\n            {\n                return 1;\n            }\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    else\n    {\n        throw new System.Exception(\"Not supported\");\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic long Fibonacci(int n)\n{\n    if (n == 0)\n    {\n        return 0;\n    }\n\n    if (n == 1)\n    {\n        return 1;\n    }\n\n    if (n > 50)\n    {\n        throw new System.Exception(\"Not supported\");\n    }\n\n    return Fibonacci(n - 1) + Fibonacci(n - 2);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid mental mapping</b></summary>\n\nDon’t force the reader of your code to translate what the variable means. **Explicit is better than implicit**.\n\n**Bad:**\n\n```csharp\nvar l = new[] { \"Austin\", \"New York\", \"San Francisco\" };\n\nfor (var i = 0; i < l.Count(); i++)\n{\n    var li = l[i];\n    DoStuff();\n    DoSomeOtherStuff();\n\n    // ...\n    // ...\n    // ...\n    // Wait, what is `li` for again?\n    Dispatch(li);\n}\n```\n\n**Good:**\n\n```csharp\nvar locations = [\"Austin\", \"New York\", \"San Francisco\"];\n\nforeach (var location in locations)\n{\n    DoStuff();\n    DoSomeOtherStuff();\n\n    // ...\n    // ...\n    // ...\n    Dispatch(location);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid magic string</b></summary>\n\nMagic strings are string values that are specified directly within application code that have an impact on the application’s behavior. Frequently, such strings will end up being duplicated within the system, and since they cannot automatically be updated using refactoring tools, they become a common source of bugs when changes are made to some strings but not others.\n\n**Bad**\n\n```csharp\nif (userRole == \"Admin\")\n{\n    // logic in here\n}\n```\n\n**Good**\n\n```csharp\nconst string ADMIN_ROLE = \"Admin\"\nif (userRole == ADMIN_ROLE)\n{\n    // logic in here\n}\n```\n\nUsing this we only have to change in centralize place and others will adapt it.\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't add unneeded context</b></summary>\n\nIf your class/object name tells you something, don't repeat that in your variable name.\n\n**Bad:**\n\n```csharp\npublic class Car\n{\n    public string CarMake { get; set; }\n    public string CarModel { get; set; }\n    public string CarColor { get; set; }\n\n    //...\n}\n```\n\n**Good:**\n\n```csharp\npublic class Car\n{\n    public string Make { get; set; }\n    public string Model { get; set; }\n    public string Color { get; set; }\n\n    //...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use meaningful and pronounceable variable names</b></summary>\n\n**Bad:**\n\n```csharp\nvar ymdstr = DateTime.UtcNow.ToString(\"MMMM dd, yyyy\");\n```\n\n**Good:**\n\n```csharp\nvar currentDate = DateTime.UtcNow.ToString(\"MMMM dd, yyyy\");\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use the same vocabulary for the same type of variable</b></summary>\n\n**Bad:**\n\n```csharp\nGetUserInfo();\nGetUserData();\nGetUserRecord();\nGetUserProfile();\n```\n\n**Good:**\n\n```csharp\nGetUser();\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use searchable names (part 1)</b></summary>\n\nWe will read more code than we will ever write. It's important that the code we do write is readable and searchable. By _not_ naming variables that end up being meaningful for understanding our program, we hurt our readers. Make your names searchable.\n\n**Bad:**\n\n```csharp\n// What the heck is data for?\nvar data = new { Name = \"John\", Age = 42 };\n\nvar stream1 = new MemoryStream();\nvar ser1 = new DataContractJsonSerializer(typeof(object));\nser1.WriteObject(stream1, data);\n\nstream1.Position = 0;\nvar sr1 = new StreamReader(stream1);\nConsole.Write(\"JSON form of Data object: \");\nConsole.WriteLine(sr1.ReadToEnd());\n```\n\n**Good:**\n\n```csharp\nvar person = new Person\n{\n    Name = \"John\",\n    Age = 42\n};\n\nvar stream2 = new MemoryStream();\nvar ser2 = new DataContractJsonSerializer(typeof(Person));\nser2.WriteObject(stream2, data);\n\nstream2.Position = 0;\nvar sr2 = new StreamReader(stream2);\nConsole.Write(\"JSON form of Data object: \");\nConsole.WriteLine(sr2.ReadToEnd());\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use searchable names (part 2)</b></summary>\n\n**Bad:**\n\n```csharp\nvar data = new { Name = \"John\", Age = 42, PersonAccess = 4};\n\n// What the heck is 4 for?\nif (data.PersonAccess == 4)\n{\n    // do edit ...\n}\n```\n\n**Good:**\n\n```csharp\npublic enum PersonAccess : int\n{\n    ACCESS_READ = 1,\n    ACCESS_CREATE = 2,\n    ACCESS_UPDATE = 4,\n    ACCESS_DELETE = 8\n}\n\nvar person = new Person\n{\n    Name = \"John\",\n    Age = 42,\n    PersonAccess= PersonAccess.ACCESS_CREATE\n};\n\nif (person.PersonAccess == PersonAccess.ACCESS_UPDATE)\n{\n    // do edit ...\n}\n```\n\n**[⬆ Back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use explanatory variables</b></summary>\n\n**Bad:**\n\n```csharp\nconst string Address = \"One Infinite Loop, Cupertino 95014\";\nvar cityZipCodeRegex = @\"/^[^,\\]+[,\\\\s]+(.+?)\\s*(\\d{5})?$/\";\nvar matches = Regex.Matches(Address, cityZipCodeRegex);\nif (matches[0].Success == true && matches[1].Success == true)\n{\n    SaveCityZipCode(matches[0].Value, matches[1].Value);\n}\n```\n\n**Good:**\n\nDecrease dependence on regex by naming subpatterns.\n\n```csharp\nconst string Address = \"One Infinite Loop, Cupertino 95014\";\nvar cityZipCodeWithGroupRegex = @\"/^[^,\\]+[,\\\\s]+(?<city>.+?)\\s*(?<zipCode>\\d{5})?$/\";\nvar matchesWithGroup = Regex.Match(Address, cityZipCodeWithGroupRegex);\nvar cityGroup = matchesWithGroup.Groups[\"city\"];\nvar zipCodeGroup = matchesWithGroup.Groups[\"zipCode\"];\nif(cityGroup.Success == true && zipCodeGroup.Success == true)\n{\n    SaveCityZipCode(cityGroup.Value, zipCodeGroup.Value);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use default arguments instead of short circuiting or conditionals</b></summary>\n\n**Not good:**\n\nThis is not good because `breweryName` can be `NULL`.\n\nThis opinion is more understandable than the previous version, but it better controls the value of the variable.\n\n```csharp\npublic void CreateMicrobrewery(string name = null)\n{\n    var breweryName = !string.IsNullOrEmpty(name) ? name : \"Hipster Brew Co.\";\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic void CreateMicrobrewery(string breweryName = \"Hipster Brew Co.\")\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Functions\n\n<details>\n  <summary><b>Avoid side effects</b></summary>\n\nA function produces a side effect if it does anything other than take a value in and return another value or values. A side effect could be writing to a file, modifying some global variable, or accidentally wiring all your money to a stranger.\n\nNow, you do need to have side effects in a program on occasion. Like the previous example, you might need to write to a file. What you want to do is to centralize where you are doing this. Don't have several functions and classes that write to a particular file. Have one service that does it. One and only one.\n\nThe main point is to avoid common pitfalls like sharing state between objects without any structure, using mutable data types that can be written to by anything, and not centralizing where your side effects occur. If you can do this, you will be happier\nthan the vast majority of other programmers.\n\n**Bad:**\n\n```csharp\n// Global variable referenced by following function.\n// If we had another function that used this name, now it'd be an array and it could break it.\nvar name = \"Ryan McDermott\";\n\npublic void SplitAndEnrichFullName()\n{\n    var temp = name.Split(\" \");\n    name = $\"His first name is {temp[0]}, and his last name is {temp[1]}\"; // side effect\n}\n\nSplitAndEnrichFullName();\n\nConsole.WriteLine(name); // His first name is Ryan, and his last name is McDermott\n```\n\n**Good:**\n\n```csharp\npublic string SplitAndEnrichFullName(string name)\n{\n    var temp = name.Split(\" \");\n    return $\"His first name is {temp[0]}, and his last name is {temp[1]}\";\n}\n\nvar name = \"Ryan McDermott\";\nvar fullName = SplitAndEnrichFullName(name);\n\nConsole.WriteLine(name); // Ryan McDermott\nConsole.WriteLine(fullName); // His first name is Ryan, and his last name is McDermott\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid negative conditionals</b></summary>\n\n**Bad:**\n\n```csharp\npublic bool IsDOMNodeNotPresent(string node)\n{\n    // ...\n}\n\nif (!IsDOMNodeNotPresent(node))\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic bool IsDOMNodePresent(string node)\n{\n    // ...\n}\n\nif (IsDOMNodePresent(node))\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid conditionals</b></summary>\n\nThis seems like an impossible task. Upon first hearing this, most people say, \"how am I supposed to do anything without an `if` statement?\" The answer is that you can use polymorphism to achieve the same task in many cases. The second question is usually, \"well that's great but why would I want to do that?\" The answer is a previous clean code concept we learned: a function should only do\none thing. When you have classes and functions that have `if` statements, you are telling your user that your function does more than one thing. Remember, just do one thing.\n\n**Bad:**\n\n```csharp\nclass Airplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        switch (_type)\n        {\n            case '777':\n                return GetMaxAltitude() - GetPassengerCount();\n            case 'Air Force One':\n                return GetMaxAltitude();\n            case 'Cessna':\n                return GetMaxAltitude() - GetFuelExpenditure();\n        }\n    }\n}\n```\n\n**Good:**\n\n```csharp\ninterface IAirplane\n{\n    // ...\n\n    double GetCruisingAltitude();\n}\n\nclass Boeing777 : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude() - GetPassengerCount();\n    }\n}\n\nclass AirForceOne : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude();\n    }\n}\n\nclass Cessna : IAirplane\n{\n    // ...\n\n    public double GetCruisingAltitude()\n    {\n        return GetMaxAltitude() - GetFuelExpenditure();\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid type-checking (part 1)</b></summary>\n\n**Bad:**\n\n```csharp\npublic Path TravelToTexas(object vehicle)\n{\n    if (vehicle.GetType() == typeof(Bicycle))\n    {\n        (vehicle as Bicycle).PeddleTo(new Location(\"texas\"));\n    }\n    else if (vehicle.GetType() == typeof(Car))\n    {\n        (vehicle as Car).DriveTo(new Location(\"texas\"));\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic Path TravelToTexas(Traveler vehicle)\n{\n    vehicle.TravelTo(new Location(\"texas\"));\n}\n```\n\nor\n\n```csharp\n// pattern matching\npublic Path TravelToTexas(object vehicle)\n{\n    if (vehicle is Bicycle bicycle)\n    {\n        bicycle.PeddleTo(new Location(\"texas\"));\n    }\n    else if (vehicle is Car car)\n    {\n        car.DriveTo(new Location(\"texas\"));\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid type-checking (part 2)</b></summary>\n\n**Bad:**\n\n```csharp\npublic int Combine(dynamic val1, dynamic val2)\n{\n    int value;\n    if (!int.TryParse(val1, out value) || !int.TryParse(val2, out value))\n    {\n        throw new Exception('Must be of type Number');\n    }\n\n    return val1 + val2;\n}\n```\n\n**Good:**\n\n```csharp\npublic int Combine(int val1, int val2)\n{\n    return val1 + val2;\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Avoid flags in method parameters</b></summary>\n\nA flag indicates that the method has more than one responsibility. It is best if the method only has a single responsibility. Split the method into two if a boolean parameter adds multiple responsibilities to the method.\n\n**Bad:**\n\n```csharp\npublic void CreateFile(string name, bool temp = false)\n{\n    if (temp)\n    {\n        Touch(\"./temp/\" + name);\n    }\n    else\n    {\n        Touch(name);\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic void CreateFile(string name)\n{\n    Touch(name);\n}\n\npublic void CreateTempFile(string name)\n{\n    Touch(\"./temp/\"  + name);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't write to global functions</b></summary>\n\nPolluting globals is a bad practice in many languages because you could clash with another library and the user of your API would be none-the-wiser until they get an exception in production. Let's think about an example: what if you wanted to have configuration array.\nYou could write global function like `Config()`, but it could clash with another library that tried to do the same thing.\n\n**Bad:**\n\n```csharp\npublic Dictionary<string, string> Config()\n{\n    return new Dictionary<string,string>(){\n        [\"foo\"] = \"bar\"\n    };\n}\n```\n\n**Good:**\n\n```csharp\nclass Configuration\n{\n    private Dictionary<string, string> _configuration;\n\n    public Configuration(Dictionary<string, string> configuration)\n    {\n        _configuration = configuration;\n    }\n\n    public string[] Get(string key)\n    {\n        return _configuration.ContainsKey(key) ? _configuration[key] : null;\n    }\n}\n```\n\nLoad configuration and create instance of `Configuration` class\n\n```csharp\nvar configuration = new Configuration(new Dictionary<string, string>() {\n    [\"foo\"] = \"bar\"\n});\n```\n\nAnd now you must use instance of `Configuration` in your application.\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't use a Singleton pattern</b></summary>\n\nSingleton is an [anti-pattern](https://en.wikipedia.org/wiki/Singleton_pattern). Paraphrased from Brian Button:\n\n1. They are generally used as a **global instance**, why is that so bad? Because **you hide the dependencies** of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a [code smell](https://en.wikipedia.org/wiki/Code_smell).\n2. They violate the [single responsibility principle](#single-responsibility-principle-srp): by virtue of the fact that **they control their own creation and lifecycle**.\n3. They inherently cause code to be tightly [coupled](https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29). This makes faking them out under **test rather difficult** in many cases.\n4. They carry state around for the lifetime of the application. Another hit to testing since **you can end up with a situation where tests need to be ordered** which is a big no for unit tests. Why? Because each unit test should be independent from the other.\n\nThere is also very good thoughts by [Misko Hevery](http://misko.hevery.com/about/) about the [root of problem](http://misko.hevery.com/2008/08/25/root-cause-of-singletons/).\n\n**Bad:**\n\n```csharp\nclass DBConnection\n{\n    private static DBConnection _instance;\n\n    private DBConnection()\n    {\n        // ...\n    }\n\n    public static GetInstance()\n    {\n        if (_instance == null)\n        {\n            _instance = new DBConnection();\n        }\n\n        return _instance;\n    }\n\n    // ...\n}\n\nvar singleton = DBConnection.GetInstance();\n```\n\n**Good:**\n\n```csharp\nclass DBConnection\n{\n    public DBConnection(IOptions<DbConnectionOption> options)\n    {\n        // ...\n    }\n\n    // ...\n}\n```\n\nCreate instance of `DBConnection` class and configure it with [Option pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.1).\n\n```csharp\nvar options = <resolve from IOC>;\nvar connection = new DBConnection(options);\n```\n\nAnd now you must use instance of `DBConnection` in your application.\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Function arguments (2 or fewer ideally)</b></summary>\n\nLimiting the amount of function parameters is incredibly important because it makes testing your function easier. Having more than three leads to a combinatorial explosion where you have to test tons of different cases with each separate argument.\n\nZero arguments is the ideal case. One or two arguments is ok, and three should be avoided. Anything more than that should be consolidated. Usually, if you have more than two arguments then your function is trying to do too much. In cases where it's not, most of the time a higher-level object will suffice as an argument.\n\n**Bad:**\n\n```csharp\npublic void CreateMenu(string title, string body, string buttonText, bool cancellable)\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\npublic record MenuConfig(\n    string Title,\n    string Body,\n    string ButtonText,\n    bool Cancellable);\n\nvar config = new MenuConfig(\n    Title: \"Foo\",\n    Body: \"Bar\",\n    ButtonText: \"Baz\",\n    Cancellable: true);\n\npublic void CreateMenu(MenuConfig config)\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Functions should do one thing</b></summary>\n\nThis is by far the most important rule in software engineering. When functions do more than one thing, they are harder to compose, test, and reason about. When you can isolate a function to just one action, they can be refactored easily and your code will read much\ncleaner. If you take nothing else away from this guide other than this, you'll be ahead of many developers.\n\n**Bad:**\n\n```csharp\npublic void SendEmailToListOfClients(string[] clients)\n{\n    foreach (var client in clients)\n    {\n        var clientRecord = db.Find(client);\n        if (clientRecord.IsActive())\n        {\n            Email(client);\n        }\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic void SendEmailToListOfClients(string[] clients)\n{\n    var activeClients = GetActiveClients(clients);\n    // Do some logic\n}\n\npublic List<Client> GetActiveClients(string[] clients)\n{\n    return db.Find(clients).Where(s => s.Status == \"Active\");\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Function names should say what they do</b></summary>\n\n**Bad:**\n\n```csharp\npublic class Email\n{\n    //...\n\n    public void Handle()\n    {\n        SendMail(this._to, this._subject, this._body);\n    }\n}\n\nvar message = new Email(...);\n// What is this? A handle for the message? Are we writing to a file now?\nmessage.Handle();\n```\n\n**Good:**\n\n```csharp\npublic class Email\n{\n    //...\n\n    public void Send()\n    {\n        SendMail(this._to, this._subject, this._body);\n    }\n}\n\nvar message = new Email(...);\n// Clear and obvious\nmessage.Send();\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Functions should only be one level of abstraction</b></summary>\n\n> Not finished yet\n\nWhen you have more than one level of abstraction your function is usually doing too much. Splitting up functions leads to reusability and easier testing.\n\n**Bad:**\n\n```csharp\npublic string ParseBetterJSAlternative(string code)\n{\n    var regexes = [\n        // ...\n    ];\n\n    var statements = explode(\" \", code);\n    var tokens = new string[] {};\n    foreach (var regex in regexes)\n    {\n        foreach (var statement in statements)\n        {\n            // ...\n        }\n    }\n\n    var ast = new string[] {};\n    foreach (var token in tokens)\n    {\n        // lex...\n    }\n\n    foreach (var node in ast)\n    {\n        // parse...\n    }\n}\n```\n\n**Bad too:**\n\nWe have carried out some of the functionality, but the `ParseBetterJSAlternative()` function is still very complex and not testable.\n\n```csharp\npublic string Tokenize(string code)\n{\n    var regexes = new string[]\n    {\n        // ...\n    };\n\n    var statements = explode(\" \", code);\n    var tokens = new string[] {};\n    foreach (var regex in regexes)\n    {\n        foreach (var statement in statements)\n        {\n            tokens[] = /* ... */;\n        }\n    }\n\n    return tokens;\n}\n\npublic string Lexer(string[] tokens)\n{\n    var ast = new string[] {};\n    foreach (var token in tokens)\n    {\n        ast[] = /* ... */;\n    }\n\n    return ast;\n}\n\npublic string ParseBetterJSAlternative(string code)\n{\n    var tokens = Tokenize(code);\n    var ast = Lexer(tokens);\n    foreach (var node in ast)\n    {\n        // parse...\n    }\n}\n```\n\n**Good:**\n\nThe best solution is move out the dependencies of `ParseBetterJSAlternative()` function.\n\n```csharp\nclass Tokenizer\n{\n    public string Tokenize(string code)\n    {\n        var regexes = new string[] {\n            // ...\n        };\n\n        var statements = explode(\" \", code);\n        var tokens = new string[] {};\n        foreach (var regex in regexes)\n        {\n            foreach (var statement in statements)\n            {\n                tokens[] = /* ... */;\n            }\n        }\n\n        return tokens;\n    }\n}\n\nclass Lexer\n{\n    public string Lexify(string[] tokens)\n    {\n        var ast = new[] {};\n        foreach (var token in tokens)\n        {\n            ast[] = /* ... */;\n        }\n\n        return ast;\n    }\n}\n\nclass BetterJSAlternative(Tokenizer tokenizer, Lexer lexer)\n{\n    public string Parse(string code)\n    {\n        var tokens = tokenizer.Tokenize(code);\n        var ast = lexer.Lexify(tokens);\n        foreach (var node in ast)\n        {\n            // parse...\n        }\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Function callers and callees should be close</b></summary>\n\nIf a function calls another, keep those functions vertically close in the source file. Ideally, keep the caller right above the callee. We tend to read code from top-to-bottom, like a newspaper. Because of this, make your code read that way.\n\n**Bad:**\n\n```csharp\nclass PerformanceReview\n{\n    private readonly Employee _employee;\n\n    public PerformanceReview(Employee employee)\n    {\n        _employee = employee;\n    }\n\n    private IEnumerable<PeersData> LookupPeers()\n    {\n        return db.lookup(_employee, 'peers');\n    }\n\n    private ManagerData LookupManager()\n    {\n        return db.lookup(_employee, 'manager');\n    }\n\n    private IEnumerable<PeerReviews> GetPeerReviews()\n    {\n        var peers = LookupPeers();\n        // ...\n    }\n\n    public PerfReviewData PerfReview()\n    {\n        GetPeerReviews();\n        GetManagerReview();\n        GetSelfReview();\n    }\n\n    public ManagerData GetManagerReview()\n    {\n        var manager = LookupManager();\n    }\n\n    public EmployeeData GetSelfReview()\n    {\n        // ...\n    }\n}\n\nvar  review = new PerformanceReview(employee);\nreview.PerfReview();\n```\n\n**Good:**\n\n```csharp\nclass PerformanceReview(Employee employee)\n{\n    public PerfReviewData PerfReview()\n    {\n        GetPeerReviews();\n        GetManagerReview();\n        GetSelfReview();\n    }\n\n    private IEnumerable<PeerReviews> GetPeerReviews()\n    {\n        var peers = LookupPeers();\n        // ...\n    }\n\n    private IEnumerable<PeersData> LookupPeers()\n    {\n        return db.lookup(employee, 'peers');\n    }\n\n    private ManagerData GetManagerReview()\n    {\n        var manager = LookupManager();\n        return manager;\n    }\n\n    private ManagerData LookupManager()\n    {\n        return db.lookup(employee, 'manager');\n    }\n\n    private EmployeeData GetSelfReview()\n    {\n        // ...\n    }\n}\n\nvar review = new PerformanceReview(employee);\nreview.PerfReview();\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Encapsulate conditionals</b></summary>\n\n**Bad:**\n\n```csharp\nif (article.state == \"published\")\n{\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\nif (article.IsPublished())\n{\n    // ...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Remove dead code</b></summary>\n\nDead code is just as bad as duplicate code. There's no reason to keep it in your codebase. If it's not being called, get rid of it! It will still be safe in your version history if you still need it.\n\n**Bad:**\n\n```csharp\npublic void OldRequestModule(string url)\n{\n    // ...\n}\n\npublic void NewRequestModule(string url)\n{\n    // ...\n}\n\nvar request = NewRequestModule(requestUrl);\nInventoryTracker(\"apples\", request, \"www.inventory-awesome.io\");\n```\n\n**Good:**\n\n```csharp\npublic void RequestModule(string url)\n{\n    // ...\n}\n\nvar request = RequestModule(requestUrl);\nInventoryTracker(\"apples\", request, \"www.inventory-awesome.io\");\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Objects and Data Structures\n\n<details>\n  <summary><b>Use getters and setters</b></summary>\n\nIn C# / VB.NET you can set `public`, `protected` and `private` keywords for methods.\nUsing it, you can control properties modification on an object.\n\n- When you want to do more beyond getting an object property, you don't have to look up and change every accessor in your codebase.\n- Makes adding validation simple when doing a `set`.\n- Encapsulates the internal representation.\n- Easy to add logging and error handling when getting and setting.\n- Inheriting this class, you can override default functionality.\n- You can lazy load your object's properties, let's say getting it from a server.\n\nAdditionally, this is part of Open/Closed principle, from object-oriented design principles.\n\n**Bad:**\n\n```csharp\nclass BankAccount\n{\n    public double Balance = 1000;\n}\n\nvar bankAccount = new BankAccount();\n\n// Fake buy shoes...\nbankAccount.Balance -= 100;\n```\n\n**Good:**\n\n```csharp\nclass BankAccount\n{\n    private double _balance = 0.0D;\n\n    pubic double Balance {\n        get {\n            return _balance;\n        }\n    }\n\n    public BankAccount(balance = 1000)\n    {\n       _balance = balance;\n    }\n\n    public void WithdrawBalance(int amount)\n    {\n        if (amount > _balance)\n        {\n            throw new Exception('Amount greater than available balance.');\n        }\n\n        _balance -= amount;\n    }\n\n    public void DepositBalance(int amount)\n    {\n        _balance += amount;\n    }\n}\n\nvar bankAccount = new BankAccount();\n\n// Buy shoes...\nbankAccount.WithdrawBalance(price);\n\n// Get balance\nbalance = bankAccount.Balance;\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Make objects have private/protected members</b></summary>\n\n**Bad:**\n\n```csharp\nclass Employee\n{\n    public string Name { get; set; }\n\n    public Employee(string name)\n    {\n        Name = name;\n    }\n}\n\nvar employee = new Employee(\"John Doe\");\nConsole.WriteLine(employee.Name); // Employee name: John Doe\n```\n\n**Good:**\n\n```csharp\nclass Employee(string name)\n{\n    public string Name { get; } = name;\n}\n\nvar employee = new Employee(\"John Doe\");\nConsole.WriteLine(employee.Name); // Employee name: John Doe\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Classes\n\n<details>\n  <summary><b>Use method chaining</b></summary>\n\nThis pattern is very useful and commonly used in many libraries. It allows your code to be expressive, and less verbose.\nFor that reason, use method chaining and take a look at how clean your code will be.\n\n**Good:**\n\n```csharp\npublic static class ListExtensions\n{\n    public static List<T> FluentAdd<T>(this List<T> list, T item)\n    {\n        list.Add(item);\n        return list;\n    }\n\n    public static List<T> FluentClear<T>(this List<T> list)\n    {\n        list.Clear();\n        return list;\n    }\n\n    public static List<T> FluentForEach<T>(this List<T> list, Action<T> action)\n    {\n        list.ForEach(action);\n        return list;\n    }\n\n    public static List<T> FluentInsert<T>(this List<T> list, int index, T item)\n    {\n        list.Insert(index, item);\n        return list;\n    }\n\n    public static List<T> FluentRemoveAt<T>(this List<T> list, int index)\n    {\n        list.RemoveAt(index);\n        return list;\n    }\n\n    public static List<T> FluentReverse<T>(this List<T> list)\n    {\n        list.Reverse();\n        return list;\n    }\n}\n\ninternal static void ListFluentExtensions()\n{\n    List<int> list = [1, 2, 3, 4, 5];\n    list = list\n        .FluentAdd(1)\n        .FluentInsert(0, 0)\n        .FluentRemoveAt(1)\n        .FluentReverse()\n        .FluentForEach(value => value.WriteLine())\n        .FluentClear();\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Prefer composition over inheritance</b></summary>\n\nAs stated famously in [_Design Patterns_](https://en.wikipedia.org/wiki/Design_Patterns) by the Gang of Four,\nyou should prefer composition over inheritance where you can. There are lots of good reasons to use inheritance and lots of good reasons to use composition.\n\nThe main point for this maxim is that if your mind instinctively goes for inheritance, try to think if composition could model your problem better. In some cases it can.\n\nYou might be wondering then, \"when should I use inheritance?\" It\ndepends on your problem at hand, but this is a decent list of when inheritance makes more sense than composition:\n\n1. Your inheritance represents an \"is-a\" relationship and not a \"has-a\" relationship (Human->Animal vs. User->UserDetails).\n2. You can reuse code from the base classes (Humans can move like all animals).\n3. You want to make global changes to derived classes by changing a base class (Change the caloric expenditure of all animals when they move).\n\n**Bad:**\n\n```csharp\nclass Employee\n{\n    private string Name { get; set; }\n    private string Email { get; set; }\n\n    public Employee(string name, string email)\n    {\n        Name = name;\n        Email = email;\n    }\n\n    // ...\n}\n\n// Bad because Employees \"have\" tax data.\n// EmployeeTaxData is not a type of Employee\n\nclass EmployeeTaxData : Employee\n{\n    private string Name { get; }\n    private string Email { get; }\n\n    public EmployeeTaxData(string name, string email, string ssn, string salary)\n    {\n         // ...\n    }\n\n    // ...\n}\n```\n\n**Good:**\n\n```csharp\nrecord EmployeeTaxData(string Ssn, string Salary);\n\nclass Employee(string name, string email)\n{\n    public string Name { get; } = name;\n    public string Email { get; } = email;\n    public EmployeeTaxData? TaxData { get; private set; }\n\n    public void SetTax(string ssn, double salary)\n    {\n        TaxData = new EmployeeTaxData(ssn, salary);\n    }\n\n    // ...\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## SOLID\n\n<details>\n  <summary><b>What is SOLID?</b></summary>\n\n**SOLID** is the mnemonic acronym introduced by Michael Feathers for the first five principles named by Robert Martin, which meant five basic principles of object-oriented programming and design.\n\n- [S: Single Responsibility Principle (SRP)](#single-responsibility-principle-srp)\n- [O: Open/Closed Principle (OCP)](#openclosed-principle-ocp)\n- [L: Liskov Substitution Principle (LSP)](#liskov-substitution-principle-lsp)\n- [I: Interface Segregation Principle (ISP)](#interface-segregation-principle-isp)\n- [D: Dependency Inversion Principle (DIP)](#dependency-inversion-principle-dip)\n\n</details>\n\n<details>\n  <summary><b>Single Responsibility Principle (SRP)</b></summary>\n\nAs stated in Clean Code, \"There should never be more than one reason for a class to change\". It's tempting to jam-pack a class with a lot of functionality, like when you can only take one suitcase on your flight. The issue with this is that your class won't be conceptually cohesive and it will give it many reasons to change. Minimizing the amount of times you need to change a class is important.\n\nIt's important because if too much functionality is in one class and you modify a piece of it, it can be difficult to understand how that will affect other dependent modules in your codebase.\n\n**Bad:**\n\n```csharp\nclass UserSettings\n{\n    private User User;\n\n    public UserSettings(User user)\n    {\n        User = user;\n    }\n\n    public void ChangeSettings(Settings settings)\n    {\n        if (verifyCredentials())\n        {\n            // ...\n        }\n    }\n\n    private bool VerifyCredentials()\n    {\n        // ...\n    }\n}\n```\n\n**Good:**\n\n```csharp\nclass UserAuth(User user)\n{\n    public bool VerifyCredentials()\n    {\n        // ...\n    }\n}\n\nclass UserSettings(User user)\n{\n    private readonly UserAuth _auth = new(user);\n\n    public void ChangeSettings(Settings settings)\n    {\n        if (_auth.VerifyCredentials())\n        {\n            // ...\n        }\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Open/Closed Principle (OCP)</b></summary>\n\nAs stated by Bertrand Meyer, \"software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.\" What does that mean though? This principle basically states that you should allow users to add new functionalities without changing existing code.\n\n**Bad:**\n\n```csharp\nabstract class AdapterBase\n{\n    protected string Name;\n\n    public string GetName()\n    {\n        return Name;\n    }\n}\n\nclass AjaxAdapter : AdapterBase\n{\n    public AjaxAdapter()\n    {\n        Name = \"ajaxAdapter\";\n    }\n}\n\nclass NodeAdapter : AdapterBase\n{\n    public NodeAdapter()\n    {\n        Name = \"nodeAdapter\";\n    }\n}\n\nclass HttpRequester : AdapterBase\n{\n    private readonly AdapterBase Adapter;\n\n    public HttpRequester(AdapterBase adapter)\n    {\n        Adapter = adapter;\n    }\n\n    public bool Fetch(string url)\n    {\n        var adapterName = Adapter.GetName();\n\n        if (adapterName == \"ajaxAdapter\")\n        {\n            return MakeAjaxCall(url);\n        }\n        else if (adapterName == \"httpNodeAdapter\")\n        {\n            return MakeHttpCall(url);\n        }\n    }\n\n    private bool MakeAjaxCall(string url)\n    {\n        // request and return promise\n    }\n\n    private bool MakeHttpCall(string url)\n    {\n        // request and return promise\n    }\n}\n```\n\n**Good:**\n\n```csharp\ninterface IAdapter\n{\n    bool Request(string url);\n}\n\nclass AjaxAdapter : IAdapter\n{\n    public bool Request(string url)\n    {\n        // request and return promise\n    }\n}\n\nclass NodeAdapter : IAdapter\n{\n    public bool Request(string url)\n    {\n        // request and return promise\n    }\n}\n\nclass HttpRequester\n{\n    private readonly IAdapter Adapter;\n\n    public HttpRequester(IAdapter adapter)\n    {\n        Adapter = adapter;\n    }\n\n    public bool Fetch(string url)\n    {\n        return Adapter.Request(url);\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Liskov Substitution Principle (LSP)</b></summary>\n\nThis is a scary term for a very simple concept. It's formally defined as \"If S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed,\netc.).\" That's an even scarier definition.\n\nThe best explanation for this is if you have a parent class and a child class, then the base class and child class can be used interchangeably without getting incorrect results. This might still be confusing, so let's take a look at the classic Square-Rectangle example. Mathematically, a square is a rectangle, but if you model it using the \"is-a\" relationship via inheritance, you quickly\nget into trouble.\n\n**Bad:**\n\n```csharp\nclass Rectangle\n{\n    protected double Width = 0;\n    protected double Height = 0;\n\n    public Drawable Render(double area)\n    {\n        // ...\n    }\n\n    public void SetWidth(double width)\n    {\n        Width = width;\n    }\n\n    public void SetHeight(double height)\n    {\n        Height = height;\n    }\n\n    public double GetArea()\n    {\n        return Width * Height;\n    }\n}\n\nclass Square : Rectangle\n{\n    public double SetWidth(double width)\n    {\n        Width = Height = width;\n    }\n\n    public double SetHeight(double height)\n    {\n        Width = Height = height;\n    }\n}\n\nDrawable RenderLargeRectangles(Rectangle rectangles)\n{\n    foreach (rectangle in rectangles)\n    {\n        rectangle.SetWidth(4);\n        rectangle.SetHeight(5);\n        var area = rectangle.GetArea(); // BAD: Will return 25 for Square. Should be 20.\n        rectangle.Render(area);\n    }\n}\n\nvar rectangles = new[] { new Rectangle(), new Rectangle(), new Square() };\nRenderLargeRectangles(rectangles);\n```\n\n**Good:**\n\n```csharp\nabstract class ShapeBase\n{\n    protected double Width = 0;\n    protected double Height = 0;\n\n    abstract public double GetArea();\n\n    public Drawable Render(double area)\n    {\n        // ...\n    }\n}\n\nclass Rectangle : ShapeBase\n{\n    public void SetWidth(double width)\n    {\n        Width = width;\n    }\n\n    public void SetHeight(double height)\n    {\n        Height = height;\n    }\n\n    public double GetArea()\n    {\n        return Width * Height;\n    }\n}\n\nclass Square : ShapeBase\n{\n    private double Length = 0;\n\n    public double SetLength(double length)\n    {\n        Length = length;\n    }\n\n    public double GetArea()\n    {\n        return Math.Pow(Length, 2);\n    }\n}\n\nDrawable RenderLargeRectangles(Rectangle rectangles)\n{\n    foreach (rectangle in rectangles)\n    {\n        if (rectangle is Square)\n        {\n            rectangle.SetLength(5);\n        }\n        else if (rectangle is Rectangle)\n        {\n            rectangle.SetWidth(4);\n            rectangle.SetHeight(5);\n        }\n\n        var area = rectangle.GetArea();\n        rectangle.Render(area);\n    }\n}\n\nvar shapes = [new Rectangle(), new Rectangle(), new Square()];\nRenderLargeRectangles(shapes);\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Interface Segregation Principle (ISP)</b></summary>\n\nISP states that \"Clients should not be forced to depend upon interfaces that they do not use.\"\n\nA good example to look at that demonstrates this principle is for\nclasses that require large settings objects. Not requiring clients to setup huge amounts of options is beneficial, because most of the time they won't need all of the settings. Making them optional helps prevent having a \"fat interface\".\n\n**Bad:**\n\n```csharp\npublic interface IEmployee\n{\n    void Work();\n    void Eat();\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n\n    public void Eat()\n    {\n        // ...... eating in lunch break\n    }\n}\n\npublic class Robot : IEmployee\n{\n    public void Work()\n    {\n        //.... working much more\n    }\n\n    public void Eat()\n    {\n        //.... robot can't eat, but it must implement this method\n    }\n}\n```\n\n**Good:**\n\nNot every worker is an employee, but every employee is an worker.\n\n```csharp\npublic interface IWorkable\n{\n    void Work();\n}\n\npublic interface IFeedable\n{\n    void Eat();\n}\n\npublic interface IEmployee : IFeedable, IWorkable\n{\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n\n    public void Eat()\n    {\n        //.... eating in lunch break\n    }\n}\n\n// robot can only work\npublic class Robot : IWorkable\n{\n    public void Work()\n    {\n        // ....working\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Dependency Inversion Principle (DIP)</b></summary>\n\nThis principle states two essential things:\n\n1. High-level modules should not depend on low-level modules. Both should depend on abstractions.\n2. Abstractions should not depend upon details. Details should depend on abstractions.\n\nThis can be hard to understand at first, but if you've worked with .NET/.NET Core framework, you've seen an implementation of this principle in the form of [Dependency Injection](https://martinfowler.com/articles/injection.html) (DI). While they are not identical concepts, DIP keeps high-level modules from knowing the details of its low-level modules and setting them up.\nIt can accomplish this through DI. A huge benefit of this is that it reduces the coupling between modules. Coupling is a very bad development pattern because it makes your code hard to refactor.\n\n**Bad:**\n\n```csharp\npublic abstract class EmployeeBase\n{\n    protected virtual void Work()\n    {\n        // ....working\n    }\n}\n\npublic class Human : EmployeeBase\n{\n    public override void Work()\n    {\n        //.... working much more\n    }\n}\n\npublic class Robot : EmployeeBase\n{\n    public override void Work()\n    {\n        //.... working much, much more\n    }\n}\n\npublic class Manager\n{\n    private readonly Robot _robot;\n    private readonly Human _human;\n\n    public Manager(Robot robot, Human human)\n    {\n        _robot = robot;\n        _human = human;\n    }\n\n    public void Manage()\n    {\n        _robot.Work();\n        _human.Work();\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic interface IEmployee\n{\n    void Work();\n}\n\npublic class Human : IEmployee\n{\n    public void Work()\n    {\n        // ....working\n    }\n}\n\npublic class Robot : IEmployee\n{\n    public void Work()\n    {\n        //.... working much more\n    }\n}\n\npublic class Manager(IEnumerable<IEmployee> employees)\n{\n    public void Manage()\n    {\n        foreach (var employee in employees)\n        {\n            employee.Work();\n        }\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don’t repeat yourself (DRY)</b></summary>\n\nTry to observe the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principle.\n\nDo your absolute best to avoid duplicate code. Duplicate code is bad because it means that there's more than one place to alter something if you need to change some logic.\n\nImagine if you run a restaurant and you keep track of your inventory: all your tomatoes, onions, garlic, spices, etc. If you have multiple lists that you keep this on, then all have to be updated when you serve a dish with tomatoes in them. If you only have one list, there's only one place to update!\n\nOftentimes you have duplicate code because you have two or more slightly different things, that share a lot in common, but their differences force you to have two or more separate functions that do much of the same things. Removing duplicate code means creating an abstraction that can handle this set of different things with just one function/module/class.\n\nGetting the abstraction right is critical, that's why you should follow the SOLID principles laid out in the [Classes](#classes) section. Bad abstractions can be worse than duplicate code, so be careful! Having said this, if you can make a good abstraction, do it! Don't repeat yourself, otherwise you'll find yourself updating multiple places anytime you want to change one thing.\n\n**Bad:**\n\n```csharp\npublic List<EmployeeData> ShowDeveloperList(Developers developers)\n{\n    foreach (var developers in developer)\n    {\n        var expectedSalary = developer.CalculateExpectedSalary();\n        var experience = developer.GetExperience();\n        var githubLink = developer.GetGithubLink();\n        var data = new[] {\n            expectedSalary,\n            experience,\n            githubLink\n        };\n\n        Render(data);\n    }\n}\n\npublic List<ManagerData> ShowManagerList(Manager managers)\n{\n    foreach (var manager in managers)\n    {\n        var expectedSalary = manager.CalculateExpectedSalary();\n        var experience = manager.GetExperience();\n        var githubLink = manager.GetGithubLink();\n        var data =\n        new[] {\n            expectedSalary,\n            experience,\n            githubLink\n        };\n\n        render(data);\n    }\n}\n```\n\n**Good:**\n\n```csharp\npublic List<EmployeeData> ShowList(Employee employees)\n{\n    foreach (var employee in employees)\n    {\n        var expectedSalary = employees.CalculateExpectedSalary();\n        var experience = employees.GetExperience();\n        var githubLink = employees.GetGithubLink();\n        var data =\n        [\n            expectedSalary,\n            experience,\n            githubLink\n        ];\n\n        render(data);\n    }\n}\n```\n\n**Very good:**\n\nIt is better to use a compact version of the code.\n\n```csharp\npublic List<EmployeeData> ShowList(Employee employees)\n{\n    foreach (var employee in employees)\n    {\n        render([\n            employee.CalculateExpectedSalary(),\n            employee.GetExperience(),\n            employee.GetGithubLink()\n        ]);\n    }\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Testing\n\n<details>\n  <summary><b>Basic concept of testing</b></summary>\n\nTesting is more important than shipping. If you have no tests or an\ninadequate amount, then every time you ship code you won't be sure that you didn't break anything. Deciding on what constitutes an adequate amount is up to your team, but having 100% coverage (all statements and branches) is how you achieve very high confidence and developer peace of mind. This means that in addition to having a great testing framework, you also need to use a [good coverage tool](https://docs.microsoft.com/en-us/visualstudio/test/using-code-coverage-to-determine-how-much-code-is-being-tested).\n\nThere's no excuse to not write tests. There's [plenty of good .NET test frameworks](https://github.com/thangchung/awesome-dotnet-core#testing), so find one that your team prefers. When you find one that works for your team, then aim to always write tests for every new feature/module you introduce. If your preferred method is Test Driven Development (TDD), that is great, but the main point is to just make sure you are reaching your coverage goals before launching any feature, or refactoring an existing one.\n\n</details>\n\n<details>\n  <summary><b>Single concept per test</b></summary>\n\nEnsures that your tests are laser focused and not testing miscellaenous (non-related) things, forces [AAA patern](http://wiki.c2.com/?ArrangeActAssert) used to make your codes more clean and readable.\n\n**Bad:**\n\n```csharp\n\npublic class MakeDotNetGreatAgainTests\n{\n    [Fact]\n    public void HandleDateBoundaries()\n    {\n        var date = new MyDateTime(\"1/1/2015\");\n        date.AddDays(30);\n        Assert.Equal(\"1/31/2015\", date);\n\n        date = new MyDateTime(\"2/1/2016\");\n        date.AddDays(28);\n        Assert.Equal(\"02/29/2016\", date);\n\n        date = new MyDateTime(\"2/1/2015\");\n        date.AddDays(28);\n        Assert.Equal(\"03/01/2015\", date);\n    }\n}\n\n```\n\n**Good:**\n\n```csharp\n\npublic class MakeDotNetGreatAgainTests\n{\n    [Fact]\n    public void Handle30DayMonths()\n    {\n        // Arrange\n        var date = new MyDateTime(\"1/1/2015\");\n\n        // Act\n        date.AddDays(30);\n\n        // Assert\n        Assert.Equal(\"1/31/2015\", date);\n    }\n\n    [Fact]\n    public void HandleLeapYear()\n    {\n        // Arrange\n        var date = new MyDateTime(\"2/1/2016\");\n\n        // Act\n        date.AddDays(28);\n\n        // Assert\n        Assert.Equal(\"02/29/2016\", date);\n    }\n\n    [Fact]\n    public void HandleNonLeapYear()\n    {\n        // Arrange\n        var date = new MyDateTime(\"2/1/2015\");\n\n        // Act\n        date.AddDays(28);\n\n        // Assert\n        Assert.Equal(\"03/01/2015\", date);\n    }\n}\n\n```\n\n> Soure https://www.codingblocks.net/podcast/how-to-write-amazing-unit-tests\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Concurrency\n\n<details>\n  <summary><b>Use Async/Await</b></summary>\n\n**Summary of Asynchronous Programming Guidelines**\n\n| Name              | Description                                       | Exceptions                      |\n| ----------------- | ------------------------------------------------- | ------------------------------- |\n| Avoid async void  | Prefer async Task methods over async void methods | Event handlers                  |\n| Async all the way | Don't mix blocking and async code                 | Console main method             |\n| Configure context | Use `ConfigureAwait(false)` when you can          | Methods that require con­text   |\n\n**The Async Way of Doing Things**\n\n| To Do This ...                           | Instead of This ...        | Use This             |\n| ---------------------------------------- | -------------------------- | -------------------- |\n| Retrieve the result of a background task | `Task.Wait or Task.Result` | `await`              |\n| Wait for any task to complete            | `Task.WaitAny`             | `await Task.WhenAny` |\n| Retrieve the results of multiple tasks   | `Task.WaitAll`             | `await Task.WhenAll` |\n| Wait a period of time                    | `Thread.Sleep`             | `await Task.Delay`   |\n\n**Best practice**\n\nThe async/await is the best for IO bound tasks (networking communication, database communication, http request, etc.) but it is not good to apply on computational bound tasks (traverse on the huge list, render a hugge image, etc.). Because it will release the holding thread to the thread pool and CPU/cores available will not involve to process those tasks. Therefore, we should avoid using Async/Await for computional bound tasks.\n\nFor dealing with computational bound tasks, prefer to use `Task.Factory.CreateNew` with `TaskCreationOptions` is `LongRunning`. It will start a new background thread to process a heavy computational bound task without release it back to the thread pool until the task being completed.\n\n**Know Your Tools**\n\nThere's a lot to learn about async and await, and it's natural to get a little disoriented. Here's a quick reference of solutions to common problems.\n\n**Solutions to Common Async Problems**\n\n| Problem                                         | Solution                                                                          |\n| ----------------------------------------------- | --------------------------------------------------------------------------------- |\n| Create a task to execute code                   | `Task.Run` or `TaskFactory.StartNew` (not the `Task` constructor or `Task.Start`) |\n| Create a task wrapper for an operation or event | `TaskFactory.FromAsync` or `TaskCompletionSource<T>`                              |\n| Support cancellation                            | `CancellationTokenSource` and `CancellationToken`                                 |\n| Report progress                                 | `IProgress<T>` and `Progress<T>`                                                  |\n| Handle streams of data                          | TPL Dataflow or Reactive Extensions                                               |\n| Synchronize access to a shared resource         | `SemaphoreSlim`                                                                   |\n| Asynchronously initialize a resource            | `AsyncLazy<T>`                                                                    |\n| Async-ready producer/consumer structures        | TPL Dataflow or `AsyncCollection<T>`                                              |\n\nRead the [Task-based Asynchronous Pattern (TAP) document](http://www.microsoft.com/download/en/details.aspx?id=19957).\nIt is extremely well-written, and includes guidance on API design and the proper use of async/await (including cancellation and progress reporting).\n\nThere are many new await-friendly techniques that should be used instead of the old blocking techniques. If you have any of these Old examples in your new async code, you're Doing It Wrong(TM):\n\n| Old                | New                                  | Description                                                   |\n| ------------------ | ------------------------------------ | ------------------------------------------------------------- |\n| `task.Wait`        | `await task`                         | Wait/await for a task to complete                             |\n| `task.Result`      | `await task`                         | Get the result of a completed task                            |\n| `Task.WaitAny`     | `await Task.WhenAny`                 | Wait/await for one of a collection of tasks to complete       |\n| `Task.WaitAll`     | `await Task.WhenAll`                 | Wait/await for every one of a collection of tasks to complete |\n| `Thread.Sleep`     | `await Task.Delay`                   | Wait/await for a period of time                               |\n| `Task` constructor | `Task.Run` or `TaskFactory.StartNew` | Create a code-based task                                      |\n\n> Source https://gist.github.com/jonlabelle/841146854b23b305b50fa5542f84b20c\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Error Handling\n\n<details>\n  <summary><b>Basic concept of error handling</b></summary>\n\nThrown errors are a good thing! They mean the runtime has successfully identified when something in your program has gone wrong and it's letting you know by stopping function execution on the current stack, killing the process (in .NET/.NET Core), and notifying you in the console with a stack trace.\n\n</details>\n\n<details>\n  <summary><b>Don't use 'throw ex' in catch block</b></summary>\n\nIf you need to re-throw an exception after catching it, use just 'throw'\nBy using this, you will save the stack trace. But in the bad option below,\nyou will lost the stack trace.\n\n**Bad:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n    // Any action something like roll-back or logging etc.\n    throw ex;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n    // Any action something like roll-back or logging etc.\n    throw;\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't ignore caught errors</b></summary>\n\nDoing nothing with a caught error doesn't give you the ability to ever fix or react to said error. Throwing the error isn't much better as often times it can get lost in a sea of things printed to the console. If you wrap any bit of code in a `try/catch` it means you think an error may occur there and therefore you should have a plan, or create a code path, for when it occurs.\n\n**Bad:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception ex)\n{\n    // silent exception\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    NotifyUserOfError(error);\n\n    // Another option\n    ReportErrorToService(error);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Use multiple catch block instead of if conditions.</b></summary>\n\nIf you need to take action according to type of the exception,\nyou better use multiple catch block for exception handling.\n\n**Bad:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (Exception ex)\n{\n\n    if (ex is TaskCanceledException)\n    {\n        // Take action for TaskCanceledException\n    }\n    else if (ex is TaskSchedulerException)\n    {\n        // Take action for TaskSchedulerException\n    }\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    // Do something..\n}\ncatch (TaskCanceledException ex)\n{\n    // Take action for TaskCanceledException\n}\ncatch (TaskSchedulerException ex)\n{\n    // Take action for TaskSchedulerException\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Keep exception stack trace when rethrowing exceptions</b></summary>\n\nC# allows the exception to be rethrown in a catch block using the `throw` keyword. It is a bad practice to throw a caught exception using `throw e;`. This statement resets the stack trace. Instead use `throw;`. This will keep the stack trace and provide a deeper insight about the exception.\nAnother option is to use a custom exception. Simply instantiate a new exception and set its inner exception property to the caught exception with throw `new CustomException(\"some info\", e);`. Adding information to an exception is a good practice as it will help with debugging. However, if the objective is to log an exception then use `throw;` to pass the buck to the caller.\n\n**Bad:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception ex)\n{\n    logger.LogInfo(ex);\n    throw ex;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    logger.LogInfo(error);\n    throw;\n}\n```\n\n**Good:**\n\n```csharp\ntry\n{\n    FunctionThatMightThrow();\n}\ncatch (Exception error)\n{\n    logger.LogInfo(error);\n    throw new CustomException(error);\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Formatting\n\n<details>\n  <summary><b>Uses <i>.editorconfig</i> file</b></summary>\n\n**Bad:**\n\nHas many code formatting styles in the project. For example, indent style is `space` and `tab` mixed in the project.\n\n**Good:**\n\nDefine and maintain consistent code style in your codebase with the use of an `.editorconfig` file\n\n```csharp\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n# C# files\n[*.cs]\nindent_size = 4\n# New line preferences\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_before_else = true\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_within_query_expression_clauses = true\n\n# Code files\n[*.{cs,csx,vb,vbx}]\nindent_size = 4\n\n# Indentation preferences\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_switch_labels = true\ncsharp_indent_labels = one_less_than_current\n\n# avoid this. unless absolutely necessary\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_event = false:suggestion\n\n# only use var when it's obvious what the variable type is\n# csharp_style_var_for_built_in_types = false:none\n# csharp_style_var_when_type_is_apparent = false:none\n# csharp_style_var_elsewhere = false:suggestion\n\n# use language keywords instead of BCL types\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\n# name all constant fields using PascalCase\ndotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.constant_fields_should_be_pascal_case.symbols  = constant_fields\ndotnet_naming_rule.constant_fields_should_be_pascal_case.style    = pascal_case_style\n\ndotnet_naming_symbols.constant_fields.applicable_kinds   = field\ndotnet_naming_symbols.constant_fields.required_modifiers = const\n\ndotnet_naming_style.pascal_case_style.capitalization = pascal_case\n\n# static fields should have s_ prefix\ndotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion\ndotnet_naming_rule.static_fields_should_have_prefix.symbols  = static_fields\ndotnet_naming_rule.static_fields_should_have_prefix.style    = static_prefix_style\n\ndotnet_naming_symbols.static_fields.applicable_kinds   = field\ndotnet_naming_symbols.static_fields.required_modifiers = static\n\ndotnet_naming_style.static_prefix_style.required_prefix = s_\ndotnet_naming_style.static_prefix_style.capitalization = camel_case\n\n# internal and private fields should be _camelCase\ndotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion\ndotnet_naming_rule.camel_case_for_private_internal_fields.symbols  = private_internal_fields\ndotnet_naming_rule.camel_case_for_private_internal_fields.style    = camel_case_underscore_style\n\ndotnet_naming_symbols.private_internal_fields.applicable_kinds = field\ndotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal\n\ndotnet_naming_style.camel_case_underscore_style.required_prefix = _\ndotnet_naming_style.camel_case_underscore_style.capitalization = camel_case\n\n# Code style defaults\ndotnet_sort_system_directives_first = true\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = false\n\n# Expression-level preferences\ndotnet_style_object_initializer = true:suggestion\ndotnet_style_collection_initializer = true:suggestion\ndotnet_style_explicit_tuple_names = true:suggestion\ndotnet_style_coalesce_expression = true:suggestion\ndotnet_style_null_propagation = true:suggestion\n\n# Expression-bodied members\ncsharp_style_expression_bodied_methods = false:none\ncsharp_style_expression_bodied_constructors = false:none\ncsharp_style_expression_bodied_operators = false:none\ncsharp_style_expression_bodied_properties = true:none\ncsharp_style_expression_bodied_indexers = true:none\ncsharp_style_expression_bodied_accessors = true:none\n\n# Pattern matching\ncsharp_style_pattern_matching_over_is_with_cast_check = true:suggestion\ncsharp_style_pattern_matching_over_as_with_null_check = true:suggestion\ncsharp_style_inlined_variable_declaration = true:suggestion\n\n# Null checking preferences\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_conditional_delegate_call = true:suggestion\n\n# Space preferences\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = do_not_ignore\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n\n[*.{asm,inc}]\nindent_size = 8\n\n# Xml project files\n[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]\nindent_size = 2\n\n# Xml config files\n[*.{props,targets,config,nuspec}]\nindent_size = 2\n\n[CMakeLists.txt]\nindent_size = 2\n\n[*.cmd]\nindent_size = 2\n\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n## Comments\n\n<details>\n  <summary><b>Avoid positional markers</b></summary>\n\nThey usually just add noise. Let the functions and variable names along with the proper indentation and formatting give the visual structure to your code.\n\n**Bad:**\n\n```csharp\n////////////////////////////////////////////////////////////////////////////////\n// Scope Model Instantiation\n////////////////////////////////////////////////////////////////////////////////\nvar model = new[]\n{\n    menu: 'foo',\n    nav: 'bar'\n};\n\n////////////////////////////////////////////////////////////////////////////////\n// Action setup\n////////////////////////////////////////////////////////////////////////////////\nvoid Actions()\n{\n    // ...\n};\n```\n\n**Bad:**\n\n```csharp\n\n#region Scope Model Instantiation\n\nvar model = {\n    menu: 'foo',\n    nav: 'bar'\n};\n\n#endregion\n\n#region Action setup\n\nvoid Actions() {\n    // ...\n};\n\n#endregion\n```\n\n**Good:**\n\n```csharp\nvar model = new[]\n{\n    menu: 'foo',\n    nav: 'bar'\n};\n\nvoid Actions()\n{\n    // ...\n};\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't leave commented out code in your codebase</b></summary>\n\nVersion control exists for a reason. Leave old code in your history.\n\n**Bad:**\n\n```csharp\ndoStuff();\n// doOtherStuff();\n// doSomeMoreStuff();\n// doSoMuchStuff();\n```\n\n**Good:**\n\n```csharp\ndoStuff();\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Don't have journal comments</b></summary>\n\nRemember, use version control! There's no need for dead code, commented code, and especially journal comments. Use `git log` to get history!\n\n**Bad:**\n\n```csharp\n/**\n * 2018-12-20: Removed monads, didn't understand them (RM)\n * 2017-10-01: Improved using special monads (JP)\n * 2016-02-03: Removed type-checking (LI)\n * 2015-03-14: Added combine with type-checking (JR)\n */\npublic int Combine(int a,int b)\n{\n    return a + b;\n}\n```\n\n**Good:**\n\n```csharp\npublic int Combine(int a,int b)\n{\n    return a + b;\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n<details>\n  <summary><b>Only comment things that have business logic complexity</b></summary>\n\nComments are an apology, not a requirement. Good code _mostly_ documents itself.\n\n**Bad:**\n\n```csharp\npublic int HashIt(string data)\n{\n    // The hash\n    var hash = 0;\n\n    // Length of string\n    var length = data.length;\n\n    // Loop through every character in data\n    for (var i = 0; i < length; i++)\n    {\n        // Get character code.\n        const char = data.charCodeAt(i);\n        // Make the hash\n        hash = ((hash << 5) - hash) + char;\n        // Convert to 32-bit integer\n        hash &= hash;\n    }\n}\n```\n\n**Better but still Bad:**\n\n```csharp\npublic int HashIt(string data)\n{\n    var hash = 0;\n    var length = data.length;\n    for (var i = 0; i < length; i++)\n    {\n        const char = data.charCodeAt(i);\n        hash = ((hash << 5) - hash) + char;\n\n        // Convert to 32-bit integer\n        hash &= hash;\n    }\n}\n```\n\nIf a comment explains WHAT the code is doing, it is probably a useless comment and can be implemented with a well named variable or function. The comment in the previous code could be replaced with a function named `ConvertTo32bitInt` so this comment is still useless.\nHowever it would be hard to express by code WHY the developer chose djb2 hash algorithm instead of sha-1 or another hash function. In that case a comment is acceptable.\n\n**Good:**\n\n```csharp\npublic int Hash(string data)\n{\n    var hash = 0;\n    var length = data.length;\n\n    for (var i = 0; i < length; i++)\n    {\n        var character = data[i];\n        // use of djb2 hash algorithm as it has a good compromise\n        // between speed and low collision with a very simple implementation\n        hash = ((hash << 5) - hash) + character;\n\n        hash = ConvertTo32BitInt(hash);\n    }\n    return hash;\n}\n\nprivate int ConvertTo32BitInt(int value)\n{\n    return value & value;\n}\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n</details>\n\n# Other Clean Code Resources\n\n## Other Clean Code Lists\n\n- [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript) - Clean Code concepts adapted for JavaScript\n- [clean-code-php](https://github.com/jupeter/clean-code-php) - Clean Code concepts adapted for PHP\n- [clean-code-ruby](https://github.com/uohzxela/clean-code-ruby) - Clean Code concepts adapted for Ruby\n- [clean-code-python](https://github.com/zedr/clean-code-python) - Clean Code concepts adapted for Python\n- [clean-code-typescript](https://github.com/labs42io/clean-code-typescript) - Clean Code concepts adapted for TypeScript\n- [clean-go-article](https://github.com/Pungyeon/clean-go-article) - Clean Code concepts adapted for Golang and an example how to apply [clean code in Golang](https://github.com/Pungyeon/clean-go)\n- [clean-abap](https://github.com/SAP/styleguides) - Clean Code concepts adapted for ABAP\n- [programming-principles](https://github.com/webpro/programming-principles) - Categorized overview of Programming Principles & Patterns\n- [Elixir-Code-Smells](https://github.com/lucasvegi/Elixir-Code-Smells) - Catalog of Elixir-specific code smells\n- [awesome-clean-code](https://github.com/kkisiele/awesome-clean-code) - Design principles, featured articles, tutorials, videos, code examples, blogs and books\n\n## Style Guides\n- [Google Styleguides](https://github.com/google/styleguide) - This project holds the C++ Style Guide, Swift Style Guide, Objective-C Style Guide, Java Style Guide, Python Style Guide, R Style Guide, Shell Style Guide, HTML/CSS Style Guide, JavaScript Style Guide, AngularJS Style Guide, Common Lisp Style Guide, and Vimscript Style Guide\n- [Django Styleguide](https://github.com/HackSoftware/Django-Styleguide) - Django styleguide used in HackSoft projects\n- [nodebestpractices](https://github.com/goldbergyoni/nodebestpractices) - The Node.js best practices list\n\n## Tools\n\n- [codemaid](https://github.com/codecadwallader/codemaid) - open source Visual Studio extension to cleanup and simplify our C#, C++, F#, VB, PHP, PowerShell, JSON, XAML, XML, ASP, HTML, CSS, LESS, SCSS, JavaScript and TypeScript coding\n- [Sharpen](https://github.com/sharpenrocks/Sharpen) - Visual Studio extension that intelligently introduces new C# features into your existing code base\n- [tslint-clean-code](https://github.com/Glavin001/tslint-clean-code) - TSLint rules for enforcing Clean Code\n\n## Cheatsheets\n\n- [AspNetCoreDiagnosticScenarios](https://github.com/davidfowl/AspNetCoreDiagnosticScenarios) - Examples of broken patterns in ASP.NET Core applications\n- [Clean Code](cheatsheets/Clean-Code-V2.4.pdf) - The summary of [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/dp/0132350882) book\n- [Clean Architecture](cheatsheets/Clean-Architecture-V1.0.pdf) - The summary of [Clean Architecture: A Craftsman's Guide to Software Structure and Design](https://www.amazon.com/dp/0134494164) book\n- [Modern JavaScript Cheatsheet](https://github.com/mbeaudru/modern-js-cheatsheet) - Cheatsheet for the JavaScript knowledge you will frequently encounter in modern projects\n- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org) - Cheatsheet was created to provide a concise collection of high value information on specific application security topics\n- [.NET Memory Performance Analysis](https://github.com/Maoni0/mem-doc/blob/master/doc/.NETMemoryPerformanceAnalysis.md) - This document aims to help folks who develop applications in .NET with how to think about memory performance analysis and finding the right approaches to perform such analysis if they need to. In this context .NET includes .NET Framework and .NET Core. In order to get the latest memory improvements in both the garbage collector and the rest of the framework I strongly encourage you to be on .NET Core if you are not already, because that’s where the active development happens\n- [naming-cheatsheet](https://github.com/kettanaito/naming-cheatsheet) - Comprehensive language-agnostic guidelines on variables naming\n- [101 Design Patterns & Tips for Developers](https://sourcemaking.com/design-patterns-and-tips)\n- [Go Concurrency Guide](https://github.com/luk4z7/go-concurrency-guide)\n- [Cognitive Load In Software Development](https://github.com/zakirullin/cognitive-load)\n\n---\n\n# Contributors\n\nThank you to all the people who have already contributed to `clean-code-dotnet` project\n\n<a href=\"https://github.com/thangchung/clean-code-dotnet/graphs/contributors\"><img src=\"https://opencollective.com/cleancodedotnet/contributors.svg?width=890\" title=\"contributors\" alt=\"contributors\" /></a>\n\n# Backers\n\nLove our work and help us continue our activities? [[Become a backer](https://opencollective.com/cleancodedotnet#backer)]\n\n<a href=\"https://opencollective.com/cleancodedotnet#backers\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/backers.svg?width=890\"></a>\n\n# Sponsors\n\nBecome a sponsor and get your logo in our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/cleancodedotnet#sponsor)]\n\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/cleancodedotnet/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/cleancodedotnet/sponsor/4/avatar.svg\"></a>\n\n# License\n\n[![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/)\n\nTo the extent possible under law, [thangchung](https://github.com/thangchung) has waived all copyright and related or neighboring rights to this work.\n"
  },
  {
    "path": "cheatsheets/README.md",
    "content": "Those cheatsheets actually come from sources as below:\n\nClean Code Cheatsheet (v2.4)\n=====================\n- Project: professional-programming\n- URL: https://github.com/charlax/professional-programming\n- License: MIT License\n- Git: ca449798364995c813fed490a6d241bada7cace4\n\nClean Architecture Cheatsheet (v1.0)\n=====================\n- Project: professional-programming\n- URL: https://github.com/charlax/professional-programming\n- License: MIT License\n- Git: ca449798364995c813fed490a6d241bada7cace4"
  }
]