7 Ineffective Coding Habits Many F# Programmers Don't Have


The Presentation inside:

Slide 0

7 ineffective coding habits MANY F# programmers DON’T have


Slide 1

Nov 14’ @theburningmonk now


Slide 2

BuildStuff ‘14


Slide 3


Slide 4

“I’m not a great programmer; I’m just a good programmer with great habits.” - Kent Beck


Slide 5

Noisy Code Visual Dishonesty Lego Naming Underabstraction Unencapsulated State Getters and Setters Uncohesive Tests


Slide 6

does the language I use make a difference? @theburningmonk


Slide 7

Noisy Code


Slide 8

@theburningmonk


Slide 9


Slide 10

@theburningmonk


Slide 11

every LOC is a cost @theburningmonk


Slide 12

more code more chance for bugs @theburningmonk


Slide 13

more code more engineers @theburningmonk


Slide 14

@theburningmonk


Slide 15

@theburningmonk


Slide 16

@theburningmonk


Slide 17

“Any organisation that designs a system will inevitably produce a design whose structure is a copy of the organisation’s communication structure” - Conway’s Law


Slide 18

@theburningmonk


Slide 19

@theburningmonk


Slide 20

You should do whatever possible to increase the productivity of individual programmers in terms of the expressive power of the code they write. Less code to do the same thing (and possibly better). Less programmers to hire. Less organizational communication costs. @theburningmonk


Slide 21

You should do whatever possible to increase the productivity of individual programmers in terms of the expressive power of the code they write. Less code to do the same thing (and possibly better). Less programmers to hire. Less organizational communication costs. @theburningmonk


Slide 22

does the language I use make a difference?


Slide 23

@theburningmonk


Slide 24

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 25

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 26

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 27

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 28

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 29

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 30

source http://bit.ly/1oBHHh1 @theburningmonk


Slide 31

Recap @theburningmonk


Slide 32

no { } no nulls fewer syntactic noise @theburningmonk


Slide 33

fewer code fewer noise @theburningmonk


Slide 34

fewer noise higher SNR @theburningmonk


Slide 35

fewer code fewer devs @theburningmonk


Slide 36

“Lead time to someone saying thank you is the only reputation metric that matters.” - Dan North


Slide 37

Visual Dishonesty


Slide 38

“…a clean design is one that supports visual thinking so people can meet their informational needs with a minimum of conscious effort.” - Daniel Higginbotham (www.visualmess.com)


Slide 39

public void MyCleverMethod( int firstArg, string secondArg) signifies hie rarchy @theburningmonk


Slide 40

“You convey information by the way you arrange a design’s elements in relation to each other. This information is understood immediately, if not consciously, by the people viewing your designs.” - Daniel Higginbotham (www.visualmess.com)


Slide 41

“This is great if the visual relationships are obvious and accurate, but if they’re not, your audience is going to get confused. They’ll have to examine your work carefully, going back and forth between the different parts to make sure they understand.” - Daniel Higginbotham (www.visualmess.com)


Slide 42

how we read ENGLISH Whilst talking with an ex-colleague, a question came up on how to implement the Stable Marriage problem using a message passing approach. Naturally, I wanted to answer that question with Erlang! Let’s first dissect the problem and decide what processes we need and how they need to interact with one another. The stable marriage problem is commonly stated as: Given n men and n women, where each person has ranked all members of the opposite sex with a unique number between 1 and n in order of preference, marry the men and women together such that there are no two people of opposite sex who would both rather have each other than their current partners. If there are no such people, all the marriages are “stable”. (It is assumed that the participants are binary gendered and that marriages are not same-sex). From the problem description, we can see that we need: * a module for man * a module for woman * a module for orchestrating the experiment In terms of interaction between the different modules, I imagined something along the lines of… see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 43

how we read ENGLISH Whilst talking with an ex-colleague, a question came up on how to implement the Stable Marriage problem using a message passing approach. Naturally, I wanted to answer that question with Erlang! 1.left-to-right Let’s first dissect the problem and decide what processes we need and how they need to interact with one another. 2. top-to-bottom The stable marriage problem is commonly stated as: Given n men and n women, where each person has ranked all members of the opposite sex with a unique number between 1 and n in order of preference, marry the men and women together such that there are no two people of opposite sex who would both rather have each other than their current partners. If there are no such people, all the marriages are “stable”. (It is assumed that the participants are binary gendered and that marriages are not same-sex). From the problem description, we can see that we need: * a module for man * a module for woman * a module for orchestrating the experiment In terms of interaction between the different modules, I imagined something along the lines of… see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 44

how we read CODE public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 45

how we read CODE 2. bottom-to-top public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } 1.right-to-left see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 46

Whilst talking with an ex-colleague, a question came up on how to implement the Stable Marriage problem using a message passing approach. Naturally, I wanted to answer that question with Erlang! how we read CODE 1.left-to-right The stable marriage problem is commonly stated as: Given n men and n women, where each person has ranked all members of the opposite sex with a unique number between 1 and n in order of preference, marry the men and women together such that there are no two people of opposite sex who would both rather have each other than their current partners. If there are no such people, all the marriages are “stable”. (It is assumed that the participants are binary gendered and that marriages are not same-sex). From the problem description, we can see that we need: * a module for man * a module for woman * a module for orchestrating the experiment In terms of interaction between the different modules, I imagined something along the lines of… 2. top-to-bottom 2. top-to-bottom Let’s first dissect the problem and decide what processes we need and how they need to interact with one another. public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } how we read ENGLISH 1.right-to-left see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 47

> | see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 48

how we read CODE let drawCircle x y radius = radius |> circle |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y) see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 49

how we read CODE 1.left-to-right 2. top-to-bottom let drawCircle x y radius = radius |> circle |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y) see also http://bit.ly/1KN8cd0 @theburningmonk


Slide 50

{} @theburningmonk


Slide 51

public ResultType MyCleverMethod( int firstArg, string secondArg, string thirdArg) { var localVar = AnotherCleverMethod(firstArg, secondArg); if (localVar.IsSomething( thirdArg, MY_CONSTANT)) { DoSomething(localVar); } return localVar.GetSomething(); } @theburningmonk


Slide 52

XXXXXX XXXXXXXXXX XXXXXXXXXXXXXX XXX XXXXXXXX XXXXXX XXXXXXXXX XXXXXX XXXXXXXX XXX XXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXX XXXXXXXXX XX XXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXX XXXXXXXX XXXXXXXXXXXX @theburningmonk


Slide 53

public ResultType MyCleverMethod( int firstArg, string secondArg, string thirdArg) { var localVar = AnotherCleverMethod(firstArg, secondArg); if (localVar.IsSomething( thirdArg, MY_CONSTANT)) { DoSomething(localVar); } return localVar.GetSomething(); } @theburningmonk


Slide 54

“This is great if the visual relationships are obvious and accurate, but if they’re not, your audience is going to get confused. They’ll have to examine your work carefully, going back and forth between the different parts to make sure they understand.”


Slide 55

public ResultType MyCleverMethod( int firstArg, string secondArg, string thirdArg) { var localVar = AnotherCleverMethod(firstArg, secondArg); if (localVar.IsSomething( thirdArg, MY_CONSTANT)) { DoSomething(localVar); } return localVar.GetSomething(); } @theburningmonk


Slide 56

XXXXXX XXXXXXXXXX XXXXXXXXXXXXXX XXX XXXXXXXX XXXXXX XXXXXXXXX XXXXXX XXXXXXXX XXX XXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXX XXXXXXXXX XX XXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXX XXXXXXXX XXXXXXXXXXXX @theburningmonk


Slide 57

“It turns out that style matters in programming for the same reason that it matters in writing. It makes for better reading.” - Douglas Crockford


Slide 58

two competing rules for structuring code in C-style languages @theburningmonk


Slide 59

Compiler Human {} { } + whitespace @theburningmonk


Slide 60

what if…? @theburningmonk


Slide 61

Compiler Human whitespace whitespace @theburningmonk


Slide 62

xxx { } xxx { } @theburningmonk no braces no problem


Slide 63

There should be one - and preferably only one - obvious way to do it. - the Zen of Python @theburningmonk


Slide 64

let myCleverFunction x y z = let localVar = anotherCleverFunction x y if localVar.IsSomething(z, MY_CONSTANT) then doSomething localVar localVar.GetSomething() @theburningmonk


Slide 65

XXX XXXXXXXXXXXXXXXX X X X XXX XXXXXXXX XXXXXXXXXXXXXXXXXXXX X X XX XXXXXXXX XXXXXXXXXXX X XXXXXXXXXX XXXX XXXXXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXXXXXX @theburningmonk


Slide 66

You should do whatever possible to increase the productivity of individual programmers in terms of the expressive power of the code they write. Less code to do the same thing (and possibly better). Less programmers to hire. Less organizational communication costs. @theburningmonk


Slide 67

Recap @theburningmonk


Slide 68

|> @theburningmonk


Slide 69

one way to describe hierarchy @theburningmonk


Slide 70

Lego Naming


Slide 71

naming is HARD @theburningmonk


Slide 72

“There are only two hard things in Computer Science: cache invalidation and naming things.” - Phil Karlton


Slide 73

“Names are the one and only tool you have to explain what a variable does in every place it appears, without having to scatter comments everywhere.” - Mike Mahemoff


Slide 74

Lego Naming Gluing common words together in an attempt to create meaning. @theburningmonk


Slide 75

Remove Do Strategy Check Create Enable Controller Service Process Proxy Object Factory Exception Add Update Disable Get Set @theburningmonk Validate


Slide 76

see http://methodnamer.com @theburningmonk


Slide 77

this is not naming @theburningmonk


Slide 78

this is not naming this is labelling @theburningmonk


Slide 79

@theburningmonk


Slide 80


Slide 81

naming is HARD @theburningmonk


Slide 82

anonymous functions aka lambdas @theburningmonk


Slide 83

fewer things to name @theburningmonk


Slide 84

words |> Array.map (fun x -> x.Count) |> Array.reduce (+) @theburningmonk


Slide 85

smaller scope shorter names @theburningmonk


Slide 86

@theburningmonk


Slide 87

When x, y, and z are great variable names http://bit.ly/1ZpAByu @theburningmonk


Slide 88

"The length of a name should be related to the length of the scope. You can use very short variable names for tiny scopes, but for big scopes you should use longer names. Variable names like i and j are just fine if their scope is five lines long." - Robert C. Martin @theburningmonk


Slide 89

@theburningmonk


Slide 90

tuples + pattern matching @theburningmonk


Slide 91

tuples + pattern matching fewer abstractions @theburningmonk


Slide 92

tuples + pattern matching fewer abstractions fewer things to name @theburningmonk


Slide 93

words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len) @theburningmonk


Slide 94

words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len) @theburningmonk


Slide 95

words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len) @theburningmonk


Slide 96

words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len) @theburningmonk


Slide 97

Lego Naming can also be the symptom of a failure to identify the right level of abstractions. @theburningmonk


Slide 98

the RIGHT level of abstraction might be smaller than “object” @theburningmonk


Slide 99

public interface ConditionChecker { bool CheckCondition(); } @theburningmonk


Slide 100

public interface Condition { bool IsTrue(); } @theburningmonk


Slide 101

@theburningmonk


Slide 102

type Condition = unit -> bool @theburningmonk


Slide 103

source https://vimeo.com/113588389


Slide 104

ClassNotFoundException IllegalArgumentException IndexOutOfBoundsException NoSuchMethodException UnsupportedOperationException @theburningmonk


Slide 105

ClassNotFound IllegalArgument IndexOutOfBounds NoSuchMethod UnsupportedOperation @theburningmonk


Slide 106

ArithmeticException ArrayStoreException ClassCastException InstantiationException NullPointerException SecurityException @theburningmonk


Slide 107

IntegerDivisionByZero IllegalArrayElementType CastToNonSubclass ClassCannotBeInstantiated NullDereferenced SecurityViolation @theburningmonk


Slide 108

lightweight exception syntax @theburningmonk


Slide 109

open System open System.IO exception InsufficientBytes @theburningmonk


Slide 110

open System open System.IO exception InsufficientBytes what could this type represe @theburningmonk nt?


Slide 111

Recap @theburningmonk


Slide 112

F# < > silver bullet @theburningmonk


Slide 113

anonymous functions fewer things to name @theburningmonk


Slide 114

short names @theburningmonk


Slide 115

tuple + pattern matching fewer things to name @theburningmonk


Slide 116

no abstraction is too small @theburningmonk


Slide 117

lightweight exception syntax @theburningmonk


Slide 118

Underabstraction


Slide 119

@theburningmonk


Slide 120

public Result DoSomething( int a, string b, string c, string d, DateTime e, DateTime f, string g, MyEnum h) @theburningmonk


Slide 121

“If you have a procedure with ten parameters, you probably missed some.” - Alan Perlis


Slide 122

source https://vimeo.com/97507575


Slide 123

lightweight syntax for types and hierarchies @theburningmonk


Slide 124

record @theburningmonk


Slide 125

type Employee = { FirstName : string Surname : string Salary : int<Pound> } @theburningmonk


Slide 126

type Employee = { FirstName : string Surname : string Salary : int<Pound> } immutable by default @theburningmonk


Slide 127

let promote emp raise = { emp with Salary <- emp.Salary + raise } @theburningmonk


Slide 128

type Employee = { FirstName : string Surname : string Salary : int<Pound> } it-of-measure un @theburningmonk


Slide 129

[<Measure>] type Pound e.g. 42<Pound> 153<Pound> @theburningmonk


Slide 130

10<Meter> / 2<Second> = 5<Meter/Second> 10<Meter> * 2<Second> = 20<Meter Second> 10<Meter> + 10<Meter> = 20<Meter> 10<Meter> * 10 = 100<Meter> 10<Meter> * 10<Meter> = 100<Meter2> 10<Meter> + 2<Second> // error 10<Meter> + 2 // error


Slide 131

10<Meter> / 2<Second> = 5<Meter/Second> 10<Meter> * 2<Second> = 20<Meter Second> 10<Meter> + 10<Meter> = 20<Meter> 10<Meter> * 10 = 100<Meter> 10<Meter> * 10<Meter> = 100<Meter2> 10<Meter> + 2<Second> // error 10<Meter> + 2 // error


Slide 132

discriminated unions @theburningmonk


Slide 133

type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber @theburningmonk


Slide 134

Unencapsulated State


Slide 135

@theburningmonk


Slide 136

public class RecentlyUsedList { private List<string> items = new List<string>(); public List<string> Items { get { return items; } } … } @theburningmonk


Slide 137

immutability @theburningmonk


Slide 138

type RecentlyUsedList (?items) = let items = defaultArg items [ ] member this.Items = Array.ofList items member this.Count = List.length items member this.Add newItem = newItem::(items |> List.filter ((<>) newItem)) |> RecentlyUsedList @theburningmonk


Slide 139

Affordance an affordance is a quality of an object, or an environment, which allows an individual to perform an action. For example, a knob affords twisting, and perhaps pushing, whilst a cord affords pulling. @theburningmonk


Slide 140

source https://www.youtube.com/watch?v=aAb7hSCtvGw


Slide 141

your abstractions should afford right behaviour, whilst make it impossible to do the wrong thing @theburningmonk


Slide 142

“Make illegal states unrepresentable” - Yaron Minsky @theburningmonk


Slide 143

discriminated unions @theburningmonk


Slide 144

type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber finite, closed set of valid states ONLY @theburningmonk


Slide 145

closed hierarchy


Slide 146

no Nulls


Slide 147

match paymentMethod with | Cash -> … | Cheque chequeNum -> … | Card (cardType, cardNum) -> … @theburningmonk


Slide 148

Recap @theburningmonk


Slide 149

immutability @theburningmonk


Slide 150

make illegal state unrepresentable @theburningmonk


Slide 151

Getters and Setters


Slide 152

“When it’s not necessary to change, it’s necessary to not change.” - Lucius Cary


Slide 153

“Now we have shortcuts to do the wrong thing. We used to have type lots to do the wrong thing, not anymore.” - Kevlin Henney


Slide 154

immutability by default @theburningmonk


Slide 155

type Person = { Name : string Age : int } @theburningmonk


Slide 156

type Person = { mutable Name : string mutable Age : int } @theburningmonk


Slide 157

immutability @theburningmonk


Slide 158

Uncohesive Tests


Slide 159

When_…Then_… () When_…Then_… () When_…Then_… () MethodA When_…Then_… () When_…Then_… () When_…Then_… () @theburningmonk MethodB


Slide 160

MethodA FeatureA MethodB FeatureB MethodC @theburningmonk


Slide 161

complexities & potential bugs in the way methods work together @theburningmonk


Slide 162

…especially when states are concerned @theburningmonk


Slide 163

Test Driven Development @theburningmonk


Slide 164

“For tests to drive development they must do more than just test that code performs its required functionality: they must clearly express that required functionality to the reader. That is, they must be clear specification of the required functionality.” - Nat Pryce & Steve Freeman


Slide 165

@theburningmonk


Slide 166

how many tests? @theburningmonk


Slide 167

every test has a cost @theburningmonk


Slide 168

did we cover all the edge cases? @theburningmonk


Slide 169

Property-Based Testing (with FsCheck) @theburningmonk


Slide 170

List.rev reverse + reverse = original length of list is invariant append + reverse = reverse + prepend @theburningmonk


Slide 171

List.rev property : reverse + reverse = original let ``reverse + reverse = original`` rev aList = aList |> rev |> rev = aList Check.Quick (``reverse + reverse = original`` List.rev) // Ok, passed 100 tests. @theburningmonk


Slide 172

List.rev property : length of list is invariant let ``length of list is invariant`` rev aList = List.length (rev aList) = List.length aList Check.Quick (``length of list is invariant`` List.rev) // Ok, passed 100 tests. @theburningmonk


Slide 173

List.rev property : append + reverse = reverse + prepend let ``append + reverse = reverse + prepend`` rev x aList = (aList @ [x]) |> rev = x::(aList |> rev) Check.Quick (``append + reverse = reverse + prepend`` List.rev) // Ok, passed 100 tests. @theburningmonk


Slide 174

Check.Verbose (``append + reverse = reverse + prepend`` List.rev) // 0: ‘\005' [] 1: false ["N "] 2: “" [false; '{'] 3: ‘\017' [true; true; 'W'] 4: “" [""; false] 5: “yg]" [“H\nOq6"; null; false; false; '#'] 6: true [“"] … 11: <null> ['\014'; '0'; “\nRH”; "<#oe"; true; false; ‘O'] … @theburningmonk


Slide 175

shrinking @theburningmonk


Slide 176

Check.Quick (``append + reverse = reverse + prepend`` id) // Falsifiable, after 2 tests (4 shrinks) (StdGen (1855582125,296080469)): Original: '\013' ["}k"; ""; “"] Shrunk: true [false] @theburningmonk


Slide 177

let computers do the grunt work @theburningmonk


Slide 178

source : http://bit.ly/1kEpEso


Slide 179

Types vs Tests @theburningmonk


Slide 180

all bugs @theburningmonk


Slide 181

unknown known @theburningmonk


Slide 182

tests types @theburningmonk


Slide 183

distr. systems unit-testing system-testing @theburningmonk


Slide 184

distr. systems unit-testing system-testing property-based Jepsen @theburningmonk


Slide 185

distr. systems unit-testing system-testing property-based Jepsen types as proof TLA+ @theburningmonk


Slide 186

Noisy Code Visual Dishonesty Lego Naming Underabstraction Unencapsulated State Getters and Setters Uncohesive Tests


Slide 187

“Practice does not make perfect. Only perfect practice makes perfect.” - Vince Lombardi


Slide 188

“Perfection is not attainable. But if we chase perfection, we can catch excellence.” - Vince Lombardi


Slide 189

“Programming languages have a devious influence: they shape our thinking habits.” - Edsger W. Dijkstra


Slide 190

does the language I use make a difference? @theburningmonk


Slide 191

“I’m not a great programmer; I’m just a good programmer with great habits.” - Kent Beck


Slide 192

what about ineffective coding habits SOME F#/FP programmers DO have? @theburningmonk


Slide 193

@theburningmonk


Slide 194

people are too puritanical about purity @theburningmonk


Slide 195

@theburningmonk


Slide 196

Explicit is better than implicit. - the Zen of Python @theburningmonk


Slide 197

Simple is better than Complex. Complex is better than Complicated. - the Zen of Python @theburningmonk


Slide 198

Special cases aren't special enough to break the rules. - the Zen of Python @theburningmonk


Slide 199

Special cases aren't special enough to break the rules. Although practicality beats purity. - the Zen of Python @theburningmonk


Slide 200

If the implementation is hard to explain, it's a bad idea. - the Zen of Python @theburningmonk


Slide 201

@theburningmonk theburningmonk.com github.com/theburningmonk @theburningmonk


Slide 202

is hiring :-) http://tech.just-eat.com/jobs @theburningmonk


Slide 203


×

HTML:





Ссылка: