Slide 1

Slide 1 text

Folien von @arghrich Fixing the Billion Dollar Mistake (C# Brille) 08.02.22 richargh.de/ speakerdeck.com/richargh Richard Gross (er/ihm) Arbeitet bei maibornwolff.de/

Slide 2

Slide 2 text

Folien von @arghrich 5 € Arbeiten mit “nix” Effektives “nix” Fixing the Mistake in C#

Slide 3

Slide 3 text

Folien von @arghrich Was ist der gefÀhrlichste Fehler, den Programmierer machen? 6

Slide 4

Slide 4 text

Folien von @arghrich 2021 CWE Top 20 Most Dangerous* Software Weaknesses 7 *„most common and impactful issues experienced over the previous two calendar years.” https://cwe.mitre.org/top25/archive/2021/2021_cwe_top25.html & Comment by Jeff Atwood #15 Null Pointer Dereference Input Validation â€ș ‚Cross-Site Scripting‘ â€ș ‚OS Command Injection‘ Auth â€ș Missing Authentication / Authorization Manual Memory â€ș Out-of-bounds read/write #12 Int Overflow / Wraparound 1. // Java binary Search bug 2. binarySearch(int[] a, int key){ 3. int low = 0; 4. int high = a.length - 1; 5. 6. while (low <= high) { 7. // Bug in JDK for 20 years 8. int mid = (low + high) / 2; 9. int midVal = a[mid]; 10. // 


Slide 5

Slide 5 text

Folien von @arghrich Der Umgang mit Null ist wichtig, aber nicht der gefÀhrlichste Fehler 8

Slide 6

Slide 6 text

Folien von @arghrich Trotzdem 
 9

Slide 7

Slide 7 text

Folien von @arghrich Nur 10 Exceptions sind verantwortlich fĂŒr 97% aller geloggten Fehler 10 https://www.overops.com/blog/we-crunched-1-billion-java-logged-errors-heres-what-causes-97-of-them-2/ https://www.overops.com/blog/the-top-10-exceptions-types-in-production-java-applications-based-on-1b-events/ 97% 3% Logged Errors 10 Unique Errors Other Errors 97% der geloggten Exceptions nach HĂ€ufigkeit 1. NullPointerException 2. NumberFormatException 3. IllegalArgumentException 4. 


Slide 8

Slide 8 text

Folien von @arghrich 11 I call it my billion-dollar mistake. It was the invention of the null reference in 1965 [ALGOL]. [
] This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. Tony Hoare Null References: The Billion Dollar Mistake 2009 InnoQ Hat aber nicht C#, Java, oder Python designt. J

Slide 9

Slide 9 text

Folien von @arghrich 13 € Arbeiten mit “nix” Effektives “nix” Fixing the Mistake in C#

Slide 10

Slide 10 text

Folien von @arghrich Ein Dictionary designen 1. public class Addresses 2. { 3. private readonly Dictionary _addresses = new(); 4. 5. public Address Find(PersonId personId) 6. { 7. return _addresses[personId]; 8. } 9. // 
 14 Wenden wir das Principle of Least Surprise an: Was sollte zurĂŒckgegeben werden, wenn die personId unbekannt ist?

Slide 11

Slide 11 text

Folien von @arghrich “Nix” modellieren 15 1. public class Addresses 2. { 3. private readonly Dictionary _addresses = new(); 4. 5. public Address Find(PersonId personId) 6. { 7. return _addresses[personId]; 8. } 9. // 
 Implizit Exception C#, Python throw KeyNotFoundException Implizit return null; Java return null; Implizit return “default” C# (bei structs) return Address.NULL; return default; Explizit Verpf. Standardwert return GetOrDefault( personId, defaultAddress); Explizit “Nix” modellieren Scala, Kotlin, F#, 
 return ???;

Slide 12

Slide 12 text

Folien von @arghrich Explizites nichts 1. const address = addresses.Find(personId); 16 2. // kann nicht ignoriert werden 3. log(`Street is ${address.Street}`); 4. // Nur zugreifbar nach Check 5. if(address != null) 6. log(`${address.Street}`) Compile error Expliziter check notwendig

Slide 13

Slide 13 text

Folien von @arghrich WĂ€re es nicht toll, wenn C# explizites „nix“ hĂ€tte? 17

Slide 14

Slide 14 text

Folien von @arghrich 19 Sicherere Sprachen durch Wegfall von Optionen „Goto considered harmful“ * If, else for While return Manual memory considered harmful Garbage Collection, Reference Counting Ownership (Rust J) Implicit null considered harmful Optional Maybe T Nullable? *Edsger Dijkstra „A Case Against the Goto Statement“ aka Goto Statement Considered Harmful.

Slide 15

Slide 15 text

Folien von @arghrich F# 2005 F# empowers everyone to write succinct, robust and performant code Hat null aber man kann es nicht mehr zuweisen. 20 Rust 2010 A language empowering everyone to build reliable and efficient software. Besitzt kein null. Kotlin 2011 Modern, concise and safe programming language /* Get rid of those pesky NullPointerExceptions, you know, The Billion Dollar Mistake*/ Swift 2014 write software that is incredibly fast and safe by design. Besitzt nil fĂŒr Objective-C interop. Man erkennt einen gewissen Trend https://en.wikipedia.org/wiki/Void_safety

Slide 16

Slide 16 text

Folien von @arghrich Auch bestehende Sprachen entwickeln sich weiter 21

Slide 17

Slide 17 text

Folien von @arghrich Jeder versucht, mit Null umzugehen 22 Python Java C# https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history ‘94 ‘96 ‘02 ‘05 ‘14 ‘15 ‘19 ‘20 ‘22 C# 02 â€ș Generics â€ș Nullable Value Types â€ș Null-coalescing operator ?? C# 06 â€ș Null-propagator ?. and ?[] C# 08 .NET Core 3+ â€ș Nullable reference types C# 09 .NET 5+ â€ș Generic nullable improvements â€ș Records â€ș Init-only setters Java 8 â€ș Optional instead of nullable Python 3.5 â€ș Type hints â€ș Optional[T]

Slide 18

Slide 18 text

Folien von @arghrich 23 € Arbeiten mit “nix” Effektives “nix” Fixing the Mistake in C#

Slide 19

Slide 19 text

Folien von @arghrich Finde den Fehler 24 public string FindNotebookMaker(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return "Employee does not exist"; /* ... */ return employee.Notebook.Maker; }

Slide 20

Slide 20 text

Folien von @arghrich Warum ist das ein Fehler? public string FindNotebookMaker(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return "Employee does not exist"; /* ... */ return employee.Notebook.Maker; } 25 Aber, aber, aber, ein Employee hat immer ein notebook!!1! Ich hab das selbst so programmiert. System.NullReferenceException at FindNotebookMaker(EmployeeId id) in UsesLegacyCode.cs:line 22

Slide 21

Slide 21 text

Folien von @arghrich Der eigentliche Fehler ist wo anders public void StartRepairNotebook(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return; employee.Notebook = null; _company.Put(employee); } 26 Unter bestimmten UmstĂ€nden (z. B. wenn das Notebook repariert wird), hat ein Mitarbeiter kein Notebook. Dieses feature wurde erst viel spĂ€ter hinzugefĂŒgt oder vielleicht hast du das auch nur vergessen. Der Typ von Employee hat das nicht reflektiert. public class Employee { public EmployeeId Id {get;} public string Name {get;} public Notebook Notebook {get; set;} /*
*/ }

Slide 22

Slide 22 text

Folien von @arghrich Stack traces sind nicht hilfreich bei NullReferenceExceptions 27

Slide 23

Slide 23 text

Folien von @arghrich Nullable reference types aktivieren 1. // per *.csproj file: 2. 3. 4. 5. enable 6. 7. 8. 8.0 9. 10. 11. nullable 12. 13. 14. 28 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types 1. // per *.cs file: 2. #nullable enable 3. namespace 4. { 5. public class 6. { 7. // can now signal null 8. static string? Name() 9. { /* 
 */} 10. static ? Data() 11. { /* 
 */} 12.// disable wherever you want 13.#nullable disable OR

Slide 24

Slide 24 text

Folien von @arghrich Nach Enable (1) public void StartRepairNotebook(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return; employee.Notebook = null; _company.Put(employee); } 29 Compile error

Slide 25

Slide 25 text

Folien von @arghrich (2) Explizite nullability Modellierung 30 public class Employee { public EmployeeId Id {get;} public string Name {get;} public Notebook? Notebook {get; set;} /*
*/ } Markieren als nullable

Slide 26

Slide 26 text

Folien von @arghrich (3) Kaskadierende Compile Fehler 31 Compile Fehler public string FindNotebookMaker(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return "Employee does not exist"; /* ... */ return employee.Notebook.Maker; }

Slide 27

Slide 27 text

Folien von @arghrich Der Compiler fĂŒhrt uns durch den Code 32

Slide 28

Slide 28 text

Folien von @arghrich Wir haben die Ursache behoben, nicht nur ein Symptom 33 public string FindNotebookMaker(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return "Employee does not exist"; /* ... */ return employee.Notebook?.Maker; } public class Employee { public EmployeeId Id {get;} public string Name {get;} public Notebook? Notebook {get; set;} /*
*/ } public void StartRepairNotebook(EmployeeId id) { var employee = _company.FindById(id); if (employee is null) return; employee.Notebook = null; _company.Put(employee); }

Slide 29

Slide 29 text

Folien von @arghrich Nullable Reference Types helfen uns Bugs an der Wurzel zu beheben 34 Slides by @arghrich

Slide 30

Slide 30 text

Folien von @arghrich 36 € Arbeiten mit “nix” Effektives “nix” Fixing the Mistake in C#

Slide 31

Slide 31 text

Folien von @arghrich Recap: “Nix” modellieren 37 1. public class Addresses 2. { 3. private readonly Dictionary _addresses = new(); 4. 5. public Address Find(PersonId personId) 6. { 7. return _addresses[personId]; 8. } 9. // 
 Implizit Exception C#, Python throw KeyNotFoundException Implizit return null; Java return null; Implizit return “default” C# (bei structs) return Address.NULL; return default; Explizit Verpf. Standardwert return GetOrDefault( personId, defaultAddress); Explizit “Nix” modellieren Scala, Kotlin, F#, 
 return ???;

Slide 32

Slide 32 text

Folien von @arghrich Modellieren von “nix” in C#8 38 1. public class Addresses 2. { 3. private readonly Dictionary _addresses = new(); 4. 5. public Address? FindAddress(PersonId personId) 6. { 7. return _addresses.GetValueOrDefault(personId); 8. } 9. // 
 Explizit “Nix” modellieren Scala, Kotlin, F#, C#

Slide 33

Slide 33 text

Folien von @arghrich Umgang mit “nix” in C#8 39 1. // schlecht, kompiliert nicht 2. string? address = FindAddress(personId).Street; 3. // gut, benutzt null-propagating operator 4. string? address = FindAddress(personId)?.Street; Explizit “Nix” modellieren Scala, Kotlin, F#, C# https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/null-checking-preferences 5. // vielleicht besser, benutzt null-coalescing operator 6. string address = FindAddress(personId)?.Street ?? "Konstitucijos Av. 20”; 7. // vielleicht noch besser, nutzt null-coalescing assignment operator 8. string? address = FindAddress(personId)?.Street; 9. address ??= "Konstitucijos Av. 20”; 10.// gut, benutzt pattern matching is null check 11.if(address is null) {/*
*/} 12.if(address is not null) {/*
*/}

Slide 34

Slide 34 text

Folien von @arghrich Die EinfĂŒhrung der Nullable Reference Types sind wichtiger als Generics 40

Slide 35

Slide 35 text

Folien von @arghrich Effective Nullable reference types 42

Slide 36

Slide 36 text

Folien von @arghrich 43 #4 Immer angeben, wenn null zurĂŒckgegeben wird 1. Address? FindAddress(PersonId pId) 2. { 3. return _addresses.GetValueOrDefault(pId); 4. } 1

Slide 37

Slide 37 text

Folien von @arghrich 44 #5 Leere collections oder arrays zurĂŒckgeben, niemals null 1. // not like this 2. IList
? RecentAddresses() 3. { 4. return _employee.TrackingAllowed 5. ? _recentAddresses 6. : null; 7. } 1. // like this 2. IList
RecentAddresses() 3. { 4. return _employee.TrackingAllowed 5. ? _recentAddresses 6. : new List
(); 7. } Effective Java 3rd Edition Item 54 Erschwert die Nutzung der Api fĂŒr alle Aufrufer. 2

Slide 38

Slide 38 text

Folien von @arghrich 45 #5 C#9 records fĂŒr domain types nutzen 3 1. public class Address 2. { 3. public string City {get; init;} 4. public string? Street {get; init;} 5. // kompiliert nicht; der Compiler kann nicht wissen, dass City tatsĂ€chlich gesetzt wurde 6. } 1. public record Address( 2. string City, 3. string? Street 4. ); 1. // so wird ein Record initialisiert: 2. var address = new Address( 3. City: “Trakai”, 4. Street: null 5. )

Slide 39

Slide 39 text

Folien von @arghrich C#9 records bieten value-equality und non-destruktive Mutation 1. public record Address( 2. string City, 3. string? Street 4. ); 46 5. // value-equality 6. var address1 = new Address( 7. City: “Vilnius”, 8. Street: "Konstitucijos Av. 20" 9. ); 10. var address2 = new Address( 11. City: “Vilnius”, 12. Street: "Konstitucijos Av. 20" 13. ); 14. 15. address1 == address2 // true https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record 16.// non-destruktive Mutation 17. var address3 = address2 with { 18. Street = “Ozo g. 18” 19. } 20. address2 == address3 // false

Slide 40

Slide 40 text

Folien von @arghrich 47 #5 Vertraue nicht auf die Non-Null- Signatur am Rande deines Systems 4 1. public record EmployeeDto( 2. string Id, 3. string Name, 4. string? Email) 1. var json = @"{ ""foo"": ""bar"” }"; 2. var result = JsonConvert.DeserializeObject(json); 3. // result = EmployeeDto { Id=, Name=, Email= } 4. result.Id is null // true was unmöglich sein sollte

Slide 41

Slide 41 text

Folien von @arghrich 49 € Arbeiten mit “nix” Effektives “nix” Fixing the Mistake in C# One more thing 


Slide 42

Slide 42 text

Folien von @arghrich 50 Ich habe nullable reference types aktiviert aber jetzt habe ich null-checks ĂŒberall!!11!elf

Slide 43

Slide 43 text

Folien von @arghrich Großartig, Du hast die Fehler bereits wĂ€hrend der Compile-Time behoben 51

Slide 44

Slide 44 text

Folien von @arghrich 1. public IResponse CreateEmployee(Request request) 2. { 3. var employee = EmployeeFromBody(request.Path); 4. CheckEmailIsUnique(employee); 5. StoreEmployee(employee); 6. EmailEmployee(employee); 7. return new OkResponse(200); 8. } 52

Slide 45

Slide 45 text

Folien von @arghrich 1. public IResponse CreateEmployee(Request request) 2. { 3. var employee = EmployeeFromBody(request.Path); 4. if(employee is null) 5. { 6. return new BadResponse(400, “Employee invalid”); 7. } 8. if(EmailIsNotUnique(employee)) 9. { 10. return new BadResponse(400, “Email must be unique”); 11. } 12. StoreEmployee(employee); 13. try { 14. EmailEmployee(employee); 15. } 16. catch(ServerUnreachableException) 17. { 18. return new BadResponse(500, “could not send email”); 19. } 20. return new OkResponse(200); 21.} 53 Wo ist mein happy path hin? Kurzes Beispiel mit nur einem null-check

Slide 46

Slide 46 text

Folien von @arghrich Wie können wir die business rules wieder klar modellieren? 54

Slide 47

Slide 47 text

Folien von @arghrich Ein seichter Einstieg in das Thema Railway-Oriented Programming* 55 *By Scott Wlaschin https://fsharpforfunandprofit.com/rop/

Slide 48

Slide 48 text

Folien von @arghrich Happy Path ohne error handling 56 1. public IResponse CreateEmployee(Request request) 2. { 3. var employee = EmployeeFromBody(request.Path); 4. CheckEmailIsUnique(employee); 5. StoreEmployee(employee); 6. EmailEmployee(employee); 7. return new OkResponse(200); 8. }

Slide 49

Slide 49 text

Folien von @arghrich ROP Path mit error handling 57 1. public IResponse CreateEmployee(Request request) 2. { 3. EmployeeFromBody(request.Path).AsResult(ifnull: “invalid employee passed”) 4. .ThenTry(CheckEmailIsUnique) 5. .Then(StoreEmployee) 6. .ThenTry(EmailEmployee) 7. .Then(_ => new OkResponse(200)); 8. } Ich kann die business logic wieder sehen

Slide 50

Slide 50 text

Folien von @arghrich Fokus auf den Happy Path, Result macht den Rest 58 J L thenTry then thenTryFix thenFix 1. Result Then( 2. Func onOk){ /*
*/ } 3. Result ThenTry( 4. Func> onOk){ /*
*/ }

Slide 51

Slide 51 text

Folien von @arghrich How to get on the rail 59 J L Ok(sth) Fail(“why”) OfResult(sth?)

Slide 52

Slide 52 text

Folien von @arghrich Against Railway-Oriented Programming* 60 *Also Scott Wlaschin https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/ https://eiriktsarpalis.wordpress.com/2017/02/19/youre-better-off-using-exceptions/

Slide 53

Slide 53 text

Folien von @arghrich Don‘t wrap all exceptions with Results* 61 *Also Scott Wlaschin https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/ https://eiriktsarpalis.wordpress.com/2017/02/19/youre-better-off-using-exceptions/

Slide 54

Slide 54 text

Folien von @arghrich Use ROP only for Domain Errors* 62 *Also Scott Wlaschin https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/ https://eiriktsarpalis.wordpress.com/2017/02/19/youre-better-off-using-exceptions/

Slide 55

Slide 55 text

Folien von @arghrich How to get started? 63 Railway Oriented Programming [Original, Scott Wlaschin 2014] Against Railway-Oriented Programming [Scott Wlaschin 2019] Railway Oriented Programming: C# Edition [Tama Waddell 2019] F# nutzen J Oder Copy/Code eine eigene Result class Deep-dive talk anschauen J

Slide 56

Slide 56 text

Folien von @arghrich Jetzt simma done J 64

Slide 57

Slide 57 text

Folien von @arghrich Beispiele liegen auf Github ‱ https://github.com/Richargh/fixing-the-billion-dollar-mistake ‱ Beinhalten Beispiele in C#, F#, Java, Python, Scala ‱ Beinhalten Railway-Oriented Programming Beispiele in C# ‱ Beinhalten eine Optional-Variation von ROP in Java 65

Slide 58

Slide 58 text

Folien von @arghrich Ich bin nicht der erste, der ĂŒber nullable reference types spricht :) ‱ Null References: The Billion Dollar Mistake [Tony Hoare 2009] ‱ Nullable Reference Types in C# 8 ‱ [Jon Skeet GOTO 2019] 66

Slide 59

Slide 59 text

Folien von @arghrich Ich bin nicht der erste, der ĂŒber ROP spricht :) ‱ Railway Oriented Programming [Original, Scott Wlaschin 2014] ‱ Against Railway-Oriented Programming [Scott Wlaschin 2019] ‱ Railway Oriented Programming: C# Edition [Tama Waddell 2019] ‱ Railway-Oriented Programming in C# [Marcus Denny 2017] ‱ Railway-oriented programming in Java [Tom Johnson 2021] 67

Slide 60

Slide 60 text

Folien von @arghrich Done richargh.de/ speakerdeck.com/richargh Code at https://github.com/Richargh/fixing-the-billion-dollar-mistake Small Icons by Fontawesome Richard Gross pronoun.is/he Arbeitet bei maibornwolff.de/en Folien von @arghrich

Slide 61

Slide 61 text

Folien von @arghrich Backup

Slide 62

Slide 62 text

Folien von @arghrich 2021 CWE Top 20 Most Dangerous Software Weaknesses 1. Out-of-bounds Write 2. ‘Cross-site Scripting’ 3. Out-of-bounds Read 4. Improper Input Validation 5. ‘OS Command Injection’ 6. ‘SQL Injection’ 7. Use After Free 8. ‘Path Traversal’ 9. Cross-Site Request Forgery 10. Unrestricted File Upload with ‘Evil’ Type 11. Missing Auth. for Critical Function 12. Integer Overflow or Wraparound 13. Deserialization of Untrusted Data 14. Improper Authentication 15. NULL Pointer Dereference 16. Use of Hard-Coded Credentials 17. Improper Restriction 
 of Memory Bounds 18. Missing Authorizations 19. Incorrect Default Permissions 20. Exposure of Sensitive Information 
 70 https://cwe.mitre.org/top25/archive/2021/2021_cwe_top25.html & Comment by Jeff Atwood Rough categories Manual Memory Input Validation Auth

Slide 63

Slide 63 text

Folien von @arghrich UseCase: Change Employee Address 71 EmployeeId From Request Path Find Employee Address from Path Change Address Store changed Employee Greet Employee with new Email

Slide 64

Slide 64 text

Folien von @arghrich 1. public IResponse ChangeAddress(Request request) 2. { 3. var employeeId = EmployeeIdFromPath(request.Path); 4. var employee = _employees.FindById(employeeId); 5. var address = AddressFromBody(request.Body); 6. employee = employee.ChangeAddress(address); 7. _employees.Store(employee); 8. GreetEmployee(employee.Email); 9. return new OkResponse(200); 10.} 72 What about DbExceptions? Does not compile. All nullable.

Slide 65

Slide 65 text

Folien von @arghrich 1. public IResponse ChangeAddress(Request request) 2. { 3. var employeeId = EmployeeIdFromPath(request.Path); 4. if(employeeId is null) 5. { 6. return new BadResponse(400, “Employee Id invalid”); 7. } 8. var employee = _employees.FindById(employeeId); 9. if(employee is null) 10. { 11. return new BadResponse(400, “Employee not found”); 12. } 13. var address = AddressFromBody(request.Body); 14. if(address is null) 15. { 16. return new BadResponse(400, “address invalid”); 17. } 18. employee = employee.ChangeAddress(address); 19. try { 20. _employees.Store(employee); 21. } 22. catch(MyDbException ex) 23. { 24. return new BadResponse(500, “could not change email”); 73 Where did my happy path go?

Slide 66

Slide 66 text

Folien von @arghrich ROP Path with error handling 74 1. public IResponse ChangeAddress(Request request) 2. { 3. EmployeeIdFromPath(request.Path) 4. .ThenTry(_employees.FindById) 5. .ThenTryToPair(_ => AddressFromBody(request.Body)) 6. .ThenTry((employee, address) => employee.ChangeAddress(address)) 7. .ThenTry(_employees.Store) 8. .ThenTry(employee => GreetEmployee(employee.Email)) 9. .Then(_ => new OkResponse(200)); 10.} I can see my business logic again

Slide 67

Slide 67 text

Folien von @arghrich UseCase: Rent NotebookType 75 Employee doesn’t have a notebook Employee has enough budget? Notebook with desired type is available? Rent notebook for employee

Slide 68

Slide 68 text

Folien von @arghrich 1. public IResponse Rent(NotebookType type, EmployeeId eId) 2. { 3. var employee = _employees.FindById(eId); 4. if (AlreadyHasANotebook(employee)) 5. { 6. return Bad(”Already has a notebook); 7. } 8. var notebook = _inventory 9. .FindNotebooksByType(type) 10. .FirstOrDefault(IsAvailable); 11. 12. var budget = _budget.FindById(eId); 13. if (HasNotEnoughBudget(budget, notebook)) 14. { 15. return Bad(”Not enough budget”); 16. } 17. var remainingBudget = RentNotebook( employee, budget, notebook); 18. NotifyOfRent( employee, notebook, remainingBudget); 19. return Ok(notebook); 20.} 76 Employee doesn’t have a notebook Employee has enough budget? Notebook with desired type is available? Rent notebook for employee Notify Employee Does not compile What about DbExceptions? Negative framing

Slide 69

Slide 69 text

Folien von @arghrich 1. public IResponse Rent(NotebookType type, EmployeeId eId) 2. { 3. var employee = _employees.FindById(eId); 4. if (employee is null) 5. { 6. return Bad("Employee does not exist); 7. } 8. if (AlreadyHasANotebook(employee)) 9. { 10. return Bad(”Already has a notebook); 11. } 12. var notebook = _inventory 13. .FindNotebooksByType(type) 14. .FirstOrDefault(IsAvailable); 15. if (notebook is null) 16. { 17. return Bad("Notebook does not exist); 18. } 19. var budget = _budget.FindById(eId); 20. if (budget is null) 21. { 22. return Bad("Employee has no budget); 23. } 24. 25. if (HasNotEnoughBudget(budget, notebook)) 26. { 27. return Bad(”Not enough budget”); 28. } 29. 30. try 31. { 32. var remainingBudget = RentNotebook( employee, budget, notebook); 33. NotifyOfRent( employee, notebook, remainingBudget); 34. return Ok(notebook); 35. } 36. catch (MyDbException e) 37. { 38. Console.WriteLine(e); 39. return Bad("Could not notebook"); 40. } 41.} 77 Where did all my business rules go?

Slide 70

Slide 70 text

Folien von @arghrich 78 Goto considered very harmful, so please never use this in C# 1. [Fact(DisplayName = "We should never ever use the goto statement, it is very harmful, but note that in C# you can")] 2. void ComplexGotoExample() 3. { 4. _output.WriteLine("I'd wager this is hard to understand"); 5. var isDone = false; 6. var repeatCount = 0; 7. 8. start: 9. if (isDone) 10. goto end; 11. _output.WriteLine("First"); 12. 13. 14. 15. 16. repeat: 17. if(repeatCount > 3) 18. { 19. isDone = true; 20. goto start; 21. } 22. _output.WriteLine("Repeat"); 23. repeatCount++; 24. goto repeat; 25. 26. end: 27. _output.WriteLine("End"); 28.}