Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Workflows/Development Process

Tags:

tdd

f#

(I'm using the word "workflow" - not in the sense of async workflows - but rather in the "git workflow" sense, that is, how you use it as part of your development)

Having played around with F# for a while, I've started developing my first F# app. I'm from c#/vb. Having watched various demos/talks - rightly or wrongly- I've started off using fsi as the main development "engine" and work up stuff within that area. If I hit a problem which I need to debug, I tend to break out the problematic function into smaller bits and check those work to try and debug the problem.

However, In order to keep the amount of code manageable in fsi, once I am happy with what I have done, I the move it into a .fs and #load the .fs back into fsi. As the app gets bigger, this can begin to feel a bit clunky since when I need to refactor, I end up having to bring back in content from the fs file change it run stuff to get something working again, before pushing the code back out into the .fs file. Further this style isn't really a test first approach and so I am not getting the benefit of building a set of tests. (I can also miss the ability to set breakpoints/step the code which, istm in certain situations e.g. recursion, can be quicker for diagnosing errors than breaking out parts of a function - though maybe this is available in VS11 and I'm not setup right) .. so I think I'm perhaps not doing things optimally or else not thinking about things in the right way.

I was wondering if others could offer how they develop apps. Do you primarily use fsi or do you start with tdd. Should the tdd approach be the primary dev vehicle and FSI used more selectively to aid in the, say, implementation of more complex algorithms, data exploration etc etc

I have looked at this question and obviously it helpfully points to various tdd frameworks for F#, but I'd still be interested to find out the workflow of seasoned F# developers.

Many thx

S

like image 946
Simon Woods Avatar asked Apr 01 '13 07:04

Simon Woods


People also ask

How can I recover my Facebook password without code?

You may be able to get back into your Facebook account by using an alternate email or mobile phone number listed on your account. Using a computer or mobile phone that you have previously used to log into your Facebook account, go to facebook.com/login/identify and follow the instructions.

What is Mtouch Facebook?

Facebook Touch is an advanced Facebook app that has many distinct features. H5 apps developed it as an app made especially for touchscreen phones. Available and applicable across all smartphones, Facebook Touch offers a fine user interface and serves as an alternative to the typical Facebook App.


2 Answers

I think you're on the right track.

Development process is a matter of taste. I'll share my approach anyway.

  • Start by a few fs files. Each file represents a module, which consists of a group of functions closely related to each other. It doesn't have to be precise from beginning; you often move stuffs between modules.
  • Create a few fsx files for quick testing once skeleton of the modules is ready.
  • Create a test project and set up NuGet packages. I often use NUnit and FsUnit together.
  • Whenever fsx scripting gives correct results, move them to test cases. Do this repeatedly.
  • Include a Program.fs into the main project and compile to executable in order to debug if needed.

In general, F# REPL is the main development engine. It gives me instant feedbacks and allows incremental changes, which are very helpful in prototyping. In F#, TDD is less critical since bug rate is much lower than in other languages. And I don't test everything, just focus on main functionalities and ensure a high test coverage. Using testdriven.net add-in or Visual Studio 2012 Premium and Ultimate can give you useful statistics on test coverage.

Using F# REPL and TDD, I almost never have to use debugging. Whenever there is a wrong behaviour, I stop and think. Since your codes don't have side effects, you can reason on them easily. In many times reasoning and a few printing commands can give me the right answer.

You can use TDD in F# REPL with Unquote and FsCheck. The former offers testing via quotations, which is quite impressive. The latter uses random testing approach which is attractive in handling corner cases of your codes. I find it really useful when your programs have to satisfy certain properties. However, it may take time to learn to use these frameworks properly.

like image 78
pad Avatar answered Oct 20 '22 21:10

pad


pad gave a great answer that is very practical and useful for a person new to F#. I will give a different means so that others don't think there is only one way F#'ers do it.

Note: If you are very new to programming, then stick with pad's answer, it is much better for a new programmer.

In the Object Oriented world one thinks with objects and in such languages I would start with writing objects down on paper and working with various diagrams such as use-case, state transition, sequence diagram, etc., until I felt I had enough to start creating objects in C# cs files, fleshing out the objects with methods, properties, events, etc.

In the functional world I typically start with abstract concepts and convert them into discriminated unions (DU) in an F# fs file, skipping the use of a REPL, i.e. F# Interactive, and then start adding a few functions. After I have a few functions I set up a test project using NUnit and FsUnit via NuGet. Since the DU are abstract, the test cases are typically harder to write, so I create printers for the DU and then insert them into the test case where I capture result output from the printer in the NUnit tool, for cut and paste back into the test case making changes as necessary. See these for examples of why I don't write them from scratch by hand.

Once I have the abstract DU done, I then can move onto the code to convert the human/concrete form into the abstract DU and convert the abstract DU into human/concrete form. In some cases these would be parsers and pretty printers.

The main point I am trying to make is that I don't focus on the tools I use but on the abstract concept of the problem and bring the tools in when needed.

I will note that I also program in PROLOG and there I do start with the REPL and move the code to a store once the logic works. So I am not opposed to using a REPL, it's just a different way of approaching the problem.

EDIT

Per a request by Ken for an example.

See: Discriminated Unions (F#) and look for the section
Using Discriminated Unions Instead of Object Hierarchies

So instead of a base type of shape with inherited types of Circle, EquilateralTriangle, Square and Rectangle one would create a discriminated Union as noted:

type Shape =
| Circle of float
| EquilateralTriangle of double
| Square of double
| Rectangle of double * double

As your question would make for a much better independent question and get answers with much better detail than I can give, I would suggest you ask it.

Also if you search for info on this also search with the following substitutions for discriminated union (DU):

  • Algebraic data type
  • Generalized algebraic data type (GADT)
  • Tagged union
  • Variant
  • variant record
  • disjoint union
  • sum type
like image 30
Guy Coder Avatar answered Oct 20 '22 21:10

Guy Coder