7 ineffective coding habits many F# programmers don't have

Engineering

yan-cui
of 207
Description
Text
  • 7 ineffectivecoding habits MANY F# programmers DON’T have
  • BuildStuff ‘14
  • habit ˈhabɪt/ A settled or regular tendency or practice, especially one that is hard to give up.
  • “I’m not a great programmer; I’m just a good programmer with great habits.” - Kent Beck
  • Noisy Code Visual Dishonesty Lego Naming Underabstraction Unencapsulated State Getters and Setters Uncohesive Tests
  • @theburningmonk does the language I use make a difference?
  • “Programming languages have a devious influence: they shape our thinking habits.” - Edsger W. Dijkstra
  • Noisy Code
  • @theburningmonk
  • @theburningmonk
  • @theburningmonk every LOC is a cost
  • @theburningmonk more code more chance for bugs
  • @theburningmonk more code more engineers
  • @theburningmonk
  • @theburningmonk 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 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.
  • does the language I use make a difference?
  • @theburningmonk
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk source http://bit.ly/1oBHHh1 http://bit.ly/1oBHHh1
  • @theburningmonk Recap
  • @theburningmonk no { } no nulls fewer syntactic noise
  • @theburningmonk fewer code fewer noise
  • @theburningmonk fewer noise higher SNR
  • @theburningmonk fewer code more productivity
  • - Dan North “Lead time to someone saying thank you is the only reputation metric that matters.”
  • Visual Dishonesty
  • “…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) http://www.visualmess.com
  • @theburningmonk public void MyCleverMethod( int firstArg, string secondArg) signifies hierarchy
  • “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) http://www.visualmess.com
  • “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) http://www.visualmess.com
  • @theburningmonk 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… how we read ENGLISH see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk 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… 2. top-to-bottom 1.left-to-right how we read ENGLISH see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk how we read CODE public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk how we read CODE public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } 2. bottom -to-top 1.right-to-left see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk 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… 2. top-to-bottom 1.left-to-right how we read ENGLISH public void DoSomething(int x, int y) { Foo(y, Bar(x, Zoo(Monkey()))); } 2. top-to-bottom 1.right-to-left how we read CODE see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk |> see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk how we read CODE let drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y) see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk how we read CODE let drawCircle x y radius = circle radius |> filled (rgb 150 170 150) |> alpha 0.5 |> move (x, y) 2. top-to-bottom 1.left-to-right see also http://bit.ly/1KN8cd0 http://bit.ly/1KN8cd0
  • @theburningmonk {}
  • @theburningmonk 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 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 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(); }
  • “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.”
  • @theburningmonk 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 XXXXXX XXXXXXXXXX XXXXXXXXXXXXXX XXX XXXXXXXX XXXXXX XXXXXXXXX XXXXXX XXXXXXXX XXX XXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXX XXXXXXXXX XX XXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXXXXXX XXXXXXXXXXX XXXXXXXX XXXXXX XXXXXXXX XXXXXXXXXXXX
  • - Douglas Crockford “It turns out that style matters in programming for the same reason that it matters in writing. It makes for better reading.”
  • @theburningmonk two competing rules for structuring code in C-style languages
  • @theburningmonk Compiler { } Human { } + whitespace
  • @theburningmonk what if…?
  • @theburningmonk Compiler whitespace Human whitespace
  • @theburningmonk xxx { } xxx { } no braces no problem
  • @theburningmonk There should be one - and preferably only one - obvious way to do it. - the Zen of Python
  • @theburningmonk let myCleverFunction x y z = let localVar = anotherCleverFunction x y if localVar.IsSomething(z, MY_CONSTANT) then doSomething localVar localVar.GetSomething()
  • @theburningmonk XXX XXXXXXXXXXXXXXXX X X X XXX XXXXXXXX XXXXXXXXXXXXXXXXXXXX X X XX XXXXXXXX XXXXXXXXXXX X XXXXXXXXXX XXXX XXXXXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXXXXXX
  • @theburningmonk 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 Recap
  • @theburningmonk |>
  • @theburningmonk one way to describe hierarchy
  • Lego Naming
  • @theburningmonk naming is HARD
  • - Phil Karlton “There are only two hard things in Computer Science: cache invalidation and naming things.”
  • - Mike Mahemoff “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.”
  • @theburningmonk Lego Naming Gluing common words together in an attempt to create meaning.
  • @theburningmonk Strategy Process Create Add Controller Factory Proxy Object Exception Enable Do Disable Service Remove Check Get Set Update Validate
  • @theburningmonk see http://methodnamer.com http://methodnamer.com
  • @theburningmonk this is not naming
  • @theburningmonk this is not naming this is labelling
  • @theburningmonk
  • @theburningmonk
  • @theburningmonk naming is HARD
  • @theburningmonk anonymous functions aka lambdas
  • @theburningmonk fewer things to name
  • @theburningmonk words |> Array.map (fun x -> x.Count) |> Array.reduce (+)
  • @theburningmonk smaller scope shorter names
  • @theburningmonk
  • @theburningmonk http://bit.ly/1ZpAByu When x, y, and z are great variable names http://bit.ly/1ZpAByu
  • @theburningmonk "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 object expressions
  • @theburningmonk enterpriseCrew.OrderBy( (fun c -> c.Current), { new IComparer with member this.Compare(x, y) = x.Position.CompareTo(y.Position) })
  • @theburningmonk enterpriseCrew.OrderBy( (fun c -> c.Current), { new IComparer with member this.Compare(x, y) = x.Position.CompareTo(y.Position) })
  • @theburningmonk fewer things to name
  • @theburningmonk tuples + pattern matching
  • @theburningmonk tuples + pattern matching fewer abstractions
  • @theburningmonk tuples + pattern matching fewer abstractions fewer things to name
  • @theburningmonk words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len)
  • @theburningmonk words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len)
  • @theburningmonk words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len)
  • @theburningmonk words |> Seq.groupBy id |> Seq.map (fun (word, gr) -> word, Seq.length gr) |> Seq.iter (fun (word, len) -> printfn “%s - %s” word len)
  • @theburningmonk Lego Naming can also be the symptom of a failure to identify the right level of abstractions.
  • @theburningmonk the RIGHT level of abstraction might be smaller than “object”
  • @theburningmonk public interface ConditionChecker { bool CheckCondition(); }
  • @theburningmonk public interface Condition { bool IsTrue(); }
  • @theburningmonk
  • @theburningmonk type Condition = unit -> bool
  • source https://vimeo.com/113588389 https://vimeo.com/113588389
  • @theburningmonk ClassNotFoundException IllegalArgumentException IndexOutOfBoundsException NoSuchMethodException UnsupportedOperationException
  • @theburningmonk ClassNotFound IllegalArgument IndexOutOfBounds NoSuchMethod UnsupportedOperation
  • @theburningmonk ArithmeticException ArrayStoreException ClassCastException InstantiationException NullPointerException SecurityException
  • @theburningmonk IntegerDivisionByZero IllegalArrayElementType CastToNonSubclass ClassCannotBeInstantiated NullDereferenced SecurityViolation
  • @theburningmonk lightweight exception syntax
  • @theburningmonk open System open System.IO exception InsufficientBytes
  • @theburningmonk open System open System.IO exception InsufficientBytes what could this type represent?
  • @theburningmonk Recap
  • @theburningmonk F# < > silver bullet
  • @theburningmonk anonymous functions fewer things to name
  • @theburningmonk short names
  • @theburningmonk tuple + pattern matching fewer things to name
  • @theburningmonk no abstraction is too small
  • @theburningmonk lightweight exception syntax
  • Underabstraction
  • @theburningmonk
  • @theburningmonk public Result DoSomething( int a, string b, string c, string d, DateTime e, DateTime f, string g, MyEnum h)
  • “If you have a procedure with ten parameters, you probably missed some.” - Alan Perlis
  • source https://vimeo.com/97507575 https://vimeo.com/97507575
  • @theburningmonk lightweight syntax for types and hierarchies
  • @theburningmonk record
  • @theburningmonk type Employee = { FirstName : string Surname : string Salary : int }
  • @theburningmonk type Employee = { FirstName : string Surname : string Salary : int } immutable by default
  • @theburningmonk let promote emp raise = { emp with Salary
  • @theburningmonk mutable state complects value and time
  • @theburningmonk type Employee = { FirstName : string Surname : string Salary : int } unit-of-measure
  • @theburningmonk [] type Pound e.g. 42 153
  • 10 / 2 = 5 10 * 2 = 20 10 + 10 = 20 10 * 10 = 100 10 * 10 = 100 10 + 2 // error 10 + 2 // error
  • 10 / 2 = 5 10 * 2 = 20 10 + 10 = 20 10 * 10 = 100 10 * 10 = 100 10 + 2 // error 10 + 2 // error
  • @theburningmonk discriminated unions
  • @theburningmonk type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber
  • Unencapsulated State
  • @theburningmonk
  • @theburningmonk public class RecentlyUsedList { private List items = new List(); public List Items { get { return items; } } … }
  • @theburningmonk immutability
  • @theburningmonk 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 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.
  • source https://www.youtube.com/watch?v=aAb7hSCtvGw https://www.youtube.com/watch?v=aAb7hSCtvGw
  • @theburningmonk your abstractions should afford right behaviour, whilst make it impossible to do the wrong thing
  • @theburningmonk “Make illegal states unrepresentable” - Yaron Minsky
  • @theburningmonk discriminated unions
  • @theburningmonk type PaymentMethod = | Cash | Cheque of ChequeNumber | Card of CardType * CardNumber finite, closed set of valid states ONLY
  • closed hierarchy
  • no Nulls
  • @theburningmonk match paymentMethod with | Cash -> … | Cheque chequeNum -> … | Card (cardType, cardNum) -> …
  • @theburningmonk Recap
  • @theburningmonk immutability
  • @theburningmonk make illegal state unrepresentable
  • Getters and Setters
  • “When it’s not necessary to change, it’s necessary to not change.” - Lucius Cary
  • “Now we have shortcuts to do the wrong thing. We used to have type lots to do the wrong thing, not anymore.” - Kevlin Henney
  • @theburningmonk immutability by default
  • @theburningmonk type Person = { Name : string Age : int }
  • @theburningmonk type Person = { mutable Name : string mutable Age : int }
  • @theburningmonk immutability
  • Uncohesive Tests
  • @theburningmonk MethodA MethodB When_…Then_… () When_…Then_… () When_…Then_… () When_…Then_… () When_…Then_… () When_…Then_… ()
  • @theburningmonk MethodA MethodB MethodC FeatureA FeatureB
  • @theburningmonk complexities & potential bugs in the way methods work together
  • @theburningmonk …especially when states are concerned
  • @theburningmonk Test Driven Development
  • “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
  • @theburningmonk
  • @theburningmonk how many tests?
  • @theburningmonk every test has a cost
  • @theburningmonk did we cover all the edge cases?
  • @theburningmonk Property-Based Testing (with FsCheck)
  • @theburningmonk List.rev reverse + reverse = original length of list is invariant append + reverse = reverse + prepend
  • @theburningmonk 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 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 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 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: ['\014'; '0'; “\nRH”; "
  • @theburningmonk shrinking
  • @theburningmonk Check.Quick (``append + reverse = reverse + prepend`` id) // Falsifiable, after 2 tests (4 shrinks) (StdGen (1855582125,296080469)): Original: ‘\013' ["}k"; ""; “"] Shrunk: true [false]
  • @theburningmonk let computers do the grunt work
  • source : http://bit.ly/1kEpEso http://bit.ly/1kEpEso
  • @theburningmonk Types vs Tests
  • @theburningmonk all bugs
  • @theburningmonk unknown known
  • @theburningmonk tests types
  • @theburningmonk tests types
  • @theburningmonk unit-testing distr. systems system-testing
  • @theburningmonk Jepsenproperty-based unit-testing system-testing distr. systems
  • @theburningmonk Jepsenproperty-based unit-testing types as proof TLA+ distr. systems system-testing
  • Noisy Code Visual Dishonesty Lego Naming Underabstraction Unencapsulated State Getters and Setters Uncohesive Tests
  • “Practice does not make perfect. Only perfect practice makes perfect.” - Vince Lombardi
  • “Perfection is not attainable. But if we chase perfection, we can catch excellence.” - Vince Lombardi
  • “Programming languages have a devious influence: they shape our thinking habits.” - Edsger W. Dijkstra
  • “One of the most disastrous thing we can learn is the first programming language, even if it's a good programming language.” - Alan Kay
  • “I’m not a great programmer; I’m just a good programmer with great habits.” - Kent Beck
  • @theburningmonk what about ineffective coding habits SOME F#/FP programmers DO have?
  • @theburningmonk
  • @theburningmonk people are too puritanical about purity
  • …premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3% - Donald Knuth
  • @theburningmonk F# Map vs .Net array vs Dictionary
  • @theburningmonk
  • @theburningmonk Explicit is better than implicit. - the Zen of Python
  • @theburningmonk Simple is better than Complex. Complex is better than Complicated. - the Zen of Python
  • @theburningmonk Special cases aren't special enough to break the rules. - the Zen of Python
  • @theburningmonk Special cases aren't special enough to break the rules. Although practicality beats purity. - the Zen of Python
  • @theburningmonk If the implementation is hard to explain, it's a bad idea. - the Zen of Python
  • @theburningmonk @theburningmonk theburningmonk.com github.com/theburningmonk
  • @theburningmonk is hiring :-) http://tech.just-eat.com/jobs
Comments
Top