'

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

Понравилась презентация – покажи это...





Слайд 0

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


Слайд 1

Nov 14’ @theburningmonk now


Слайд 2

BuildStuff ‘14


Слайд 3


Слайд 4

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


Слайд 5

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


Слайд 6

does the language I use make a difference? @theburningmonk


Слайд 7

Noisy Code


Слайд 8

@theburningmonk


Слайд 9


Слайд 10

@theburningmonk


Слайд 11

every LOC is a cost @theburningmonk


Слайд 12

more code more chance for bugs @theburningmonk


Слайд 13

more code more engineers @theburningmonk


Слайд 14

@theburningmonk


Слайд 15

@theburningmonk


Слайд 16

@theburningmonk


Слайд 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


Слайд 18

@theburningmonk


Слайд 19

@theburningmonk


Слайд 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


Слайд 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


Слайд 22

does the language I use make a difference?


Слайд 23

@theburningmonk


Слайд 24

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


Слайд 25

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


Слайд 26

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


Слайд 27

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


Слайд 28

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


Слайд 29

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


Слайд 30

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


Слайд 31

Recap @theburningmonk


Слайд 32

no { } no nulls fewer syntactic noise @theburningmonk


Слайд 33

fewer code fewer noise @theburningmonk


Слайд 34

fewer noise higher SNR @theburningmonk


Слайд 35

fewer code fewer devs @theburningmonk


Слайд 36

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


Слайд 37

Visual Dishonesty


Слайд 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)


Слайд 39

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


Слайд 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)


Слайд 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)


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 47

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


Слайд 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


Слайд 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


Слайд 50

{} @theburningmonk


Слайд 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


Слайд 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


Слайд 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


Слайд 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.”


Слайд 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


Слайд 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


Слайд 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


Слайд 58

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


Слайд 59

Compiler Human {} { } + whitespace @theburningmonk


Слайд 60

what if…? @theburningmonk


Слайд 61

Compiler Human whitespace whitespace @theburningmonk


Слайд 62

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


Слайд 63

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


Слайд 64

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


Слайд 65

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


Слайд 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


Слайд 67

Recap @theburningmonk


Слайд 68

|> @theburningmonk


Слайд 69

one way to describe hierarchy @theburningmonk


Слайд 70

Lego Naming


Слайд 71

naming is HARD @theburningmonk


Слайд 72

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


Слайд 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


Слайд 74

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


Слайд 75

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


Слайд 76

see http://methodnamer.com @theburningmonk


Слайд 77

this is not naming @theburningmonk


Слайд 78

this is not naming this is labelling @theburningmonk


Слайд 79

@theburningmonk


Слайд 80


Слайд 81

naming is HARD @theburningmonk


Слайд 82

anonymous functions aka lambdas @theburningmonk


Слайд 83

fewer things to name @theburningmonk


Слайд 84

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


Слайд 85

smaller scope shorter names @theburningmonk


Слайд 86

@theburningmonk


Слайд 87

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


Слайд 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


Слайд 89

@theburningmonk


Слайд 90

tuples + pattern matching @theburningmonk


Слайд 91

tuples + pattern matching fewer abstractions @theburningmonk


Слайд 92

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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 97

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


Слайд 98

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


Слайд 99

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


Слайд 100

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


Слайд 101

@theburningmonk


Слайд 102

type Condition = unit -> bool @theburningmonk


Слайд 103

source https://vimeo.com/113588389


Слайд 104

ClassNotFoundException IllegalArgumentException IndexOutOfBoundsException NoSuchMethodException UnsupportedOperationException @theburningmonk


Слайд 105

ClassNotFound IllegalArgument IndexOutOfBounds NoSuchMethod UnsupportedOperation @theburningmonk


Слайд 106

ArithmeticException ArrayStoreException ClassCastException InstantiationException NullPointerException SecurityException @theburningmonk


Слайд 107

IntegerDivisionByZero IllegalArrayElementType CastToNonSubclass ClassCannotBeInstantiated NullDereferenced SecurityViolation @theburningmonk


Слайд 108

lightweight exception syntax @theburningmonk


Слайд 109

open System open System.IO exception InsufficientBytes @theburningmonk


Слайд 110

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


Слайд 111

Recap @theburningmonk


Слайд 112

F# < > silver bullet @theburningmonk


Слайд 113

anonymous functions fewer things to name @theburningmonk


Слайд 114

short names @theburningmonk


Слайд 115

tuple + pattern matching fewer things to name @theburningmonk


Слайд 116

no abstraction is too small @theburningmonk


Слайд 117

lightweight exception syntax @theburningmonk


Слайд 118

Underabstraction


Слайд 119

@theburningmonk


Слайд 120

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


Слайд 121

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


Слайд 122

source https://vimeo.com/97507575


Слайд 123

lightweight syntax for types and hierarchies @theburningmonk


Слайд 124

record @theburningmonk


Слайд 125

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


Слайд 126

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


Слайд 127

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


Слайд 128

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


Слайд 129

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


Слайд 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


Слайд 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


Слайд 132

discriminated unions @theburningmonk


Слайд 133

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


Слайд 134

Unencapsulated State


Слайд 135

@theburningmonk


Слайд 136

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


Слайд 137

immutability @theburningmonk


Слайд 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


Слайд 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


Слайд 140

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


Слайд 141

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


Слайд 142

“Make illegal states unrepresentable” - Yaron Minsky @theburningmonk


Слайд 143

discriminated unions @theburningmonk


Слайд 144

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


Слайд 145

closed hierarchy


Слайд 146

no Nulls


Слайд 147

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


Слайд 148

Recap @theburningmonk


Слайд 149

immutability @theburningmonk


Слайд 150

make illegal state unrepresentable @theburningmonk


Слайд 151

Getters and Setters


Слайд 152

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


Слайд 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


Слайд 154

immutability by default @theburningmonk


Слайд 155

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


Слайд 156

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


Слайд 157

immutability @theburningmonk


Слайд 158

Uncohesive Tests


Слайд 159

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


Слайд 160

MethodA FeatureA MethodB FeatureB MethodC @theburningmonk


Слайд 161

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


Слайд 162

…especially when states are concerned @theburningmonk


Слайд 163

Test Driven Development @theburningmonk


Слайд 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


Слайд 165

@theburningmonk


Слайд 166

how many tests? @theburningmonk


Слайд 167

every test has a cost @theburningmonk


Слайд 168

did we cover all the edge cases? @theburningmonk


Слайд 169

Property-Based Testing (with FsCheck) @theburningmonk


Слайд 170

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


Слайд 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


Слайд 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


Слайд 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


Слайд 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


Слайд 175

shrinking @theburningmonk


Слайд 176

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


Слайд 177

let computers do the grunt work @theburningmonk


Слайд 178

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


Слайд 179

Types vs Tests @theburningmonk


Слайд 180

all bugs @theburningmonk


Слайд 181

unknown known @theburningmonk


Слайд 182

tests types @theburningmonk


Слайд 183

distr. systems unit-testing system-testing @theburningmonk


Слайд 184

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


Слайд 185

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


Слайд 186

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


Слайд 187

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


Слайд 188

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


Слайд 189

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


Слайд 190

does the language I use make a difference? @theburningmonk


Слайд 191

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


Слайд 192

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


Слайд 193

@theburningmonk


Слайд 194

people are too puritanical about purity @theburningmonk


Слайд 195

@theburningmonk


Слайд 196

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


Слайд 197

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


Слайд 198

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


Слайд 199

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


Слайд 200

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


Слайд 201

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


Слайд 202

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


Слайд 203


×

HTML:





Ссылка: