A lot of folks miss out on some of the key tools that I use in nearly all of my projects, and I thought this issue would be a great time to share them with all of you!

Paket

First, up Paket. Paket is a fully open-source, minimal package manager for .NET that aims to integrate with NuGet, but fixes a few of the issues that drove creators to create Paket and improve the ecosystem. Paket supports all .NET languages, even Nemerle!

Dependencies are organized with three files. There's a single paket.dependencies at the solution level that lists every dependency for your whole solution. That looks something like this first example. (If you downloaded the code samples from my article in CODE Magazine's March/April 2017 issue, “Accessing Your Data with F# Type Providers,” http://www.codemag.com/Article/1703051), you'll recognize this paket.dependencies file. At the top, include a list of sources. Here, I'm using NuGet, but you can also use GitHub and HTTP. Then, list the packages you need to collect from each source.

source https://api.nuget.org/v3/index.json
nuget FsLab
nuget SwaggerProvider

Next, each project has a paket.references file listing the explicit references that the particular project will use. In this case, there's only one project, so you list both of the references from the paket.dependencies file, FsLab and SwaggerProvider.

FsLab
SwaggerProvider

Finally, a paket.lock file is generated for the entire solution, containing additional data, such as the specific version. In this case, FsLab requires several additional dependencies, and the file itself is quite large. For a sample of the file, you can look at Figure 1, but I'm not going to print the entire file for the article.

Figure 1:  A paket.lock file showing indented transitive dependencies.
Figure 1: A paket.lock file showing indented transitive dependencies.

These files make Paket use simple, thorough, and convenient.

Why should you even consider an alternative when NuGet seems perfectly sufficient? Here are a few of my favorite personal reasons.

No Package Version in the File Path

NuGet specifically includes the package version in the file path, and Paket doesn't. This change in Paket is an especially large improvement for F# script files. Because a script file can be treated as an entire project in a single file, it means that you must specifically declare your references in the file. This is most often done with a #r directive, using the full path to the dll. This means that every time you update your versions, every script you have that references the previous version no longer works. By updating the path to no longer include the explicit package version, Paket saves you a mountain of work.

By updating the path to no longer include the explicit package version, Paket saves you a mountain of work.

Transitive Dependencies

Transitive dependencies are the dependencies that the dependencies you've added have. Makes complete sense, right? Let's look at Figure 2 to make that a little more clear. Within a project that you've created, you have several dependencies. In this case, I've called out two: dependency #1 and dependency #2. Dependency #1 has a dependency that you haven't explicitly added but that will need to be included in your project for dependency #1 to function correctly. This is called a transitive dependency because you haven't yet added it to your project because you specifically needed the functionality it contains. It's only there because another dependency requires it.

When you use NuGet, all your installed packages are listed in one list, in the packages.config file, and it isn't very clear which are transitive dependencies and which are your actual dependencies. In Paket's three-file system, only your direct dependencies are listed in both the paket.references file and the paket.dependencies file. The only place that transitive dependencies appear is in the generated paket.lock file. For further clarification, they've even indented the file. As an example, look back to Figure 1 to see part of the paket.lock file from my previous article's example code.

Figure 2:  Transitive Dependencies.
Figure 2: Transitive Dependencies.

Reference Single Files

In addition to referencing files from NuGet and similar internal package management tools such as MyGet or ProGet, you can reference projects and single files straight from GitHub into your solution. You can also reference a single file through HTTP. Let's look at an example that builds on the paket.dependencies file that I showed above. First, I'll add a whole GitHub repository. This needs only the owner and repository name combo. Next, to reference a specific single file, add the path from the top-level directory in that repository. Finally, let's reference a file using HTTP. In this case, the URL doesn't end with a qualified file name, so you leave a space and create one. This downloads the file. I call it 6c.fs in this example.

source https://api.nuget.org/v3/index.json

nuget FsLab
nuget SwaggerProvider

github rachelreese/StockTicker
github rachelreese/Minesweeper MS/Utils.fs

http http://www.fssnip.net/raw/6c 6c.fs

To reference a single file into your solution using the paket.references file, preface it with File, like so:

File: Utils.fs
File: 6c.fs

You can't use the paket.references file to reference the full repository into your solution, but because the whole repository is downloaded locally, you can browse and add a specific project or file to your solution.

Only One Package Version Per Solution

If you've ever run into endless accidental dependency hell, you'll be relieved to know that Paket has the perfect fix. There's only one package version per solution. All dependencies are fully reconciled so that you don't accidentally have several versions of one transitive dependency. Now, if you must have separate versions, and you have a very good reason for needing them, it's possible to override this behavior by using dependency groups. To create a dependency group in your paket.dependencies file, just use the keyword group.

If you've ever run into endless accidental dependency hell, you'll be relieved to know that Paket has the perfect fix: one package version per solution.

For example, let's add a group containing the Azure Storage Type Provider to the same paket.dependencies file that I've been using as an example. To do so, you simply add a group with any name you like. In this case, I've chosen the name AzureTypeProvider to indicate what's contained in the group. Within the group, you'll need to add a new source and then specify the packages, repositories, or files to reference. This time, I'm only going to reference the type provider itself. The indentation isn't required, but I find that it makes it significantly more readable.

source https://api.nuget.org/v3/index.json

nuget FsLab
nuget SwaggerProvider

group AzureTypeProvider
    source https://api.nuget.org/v3/index.json

    nuget FSharp.Azure.StorageTypeProvider

Updating Framework Versions is Easier

When you reference a package with NuGet, only the correct references for the currently targeted framework version are downloaded. This is fine until you decide to upgrade framework versions. At this point, you may start finding very strange errors hidden deep in your code that you may eventually be able to trace back to using the wrong references that target the wrong framework version. When you switch framework versions, it's important to fully reinstall all packages. I've worked in plenty of shops that didn't know this. With Paket, it's not necessary to remember to reinstall. All framework versions are downloaded on install and use attributes to select the appropriate version for the currently targeted framework version.

Semantic Versioning

Finally, the issue that particularly concerns many, many developers that I see: NuGet doesn't fully support Semantic Versioning.

Semantic Versioning is a set of guidelines to use for versioning your software. It means that version numbers across several projects can make sense relative to one another. Basically, given a version number (such as 14.05.23) that's separated into three parts, you should increase:

  • The first number, 14, when you have made backward-incompatible changes
  • The second number, 05, when you have added functionality in a backward-compatible manner
  • The final number, 23, when you make backward-compatible bug fixes.

There are a few additional points for adding labels for additional data, such as 14.05.23+alpha or 14.05.23-alpha. Paket fully supports Semantic Versioning, and, as of this writing, NuGet doesn't.

Paket fully supports Semantic Versioning, and, as of this writing, NuGet doesn't.

For more information on Paket, and a few additional reasons to use it, check out https://fsprojects.github.io/Paket/faq.html.

F# Formatting

F# Formatting is a fantastic way to generate literate documentation for your projects. Although it's called F# Formatting, the project also generates literate documentation for other languages. There are a few extra special features if you're working with F# code, though.

F# Formatting works by parsing markdown files and formatting your code, and generating docs that combine both in a beautiful manner. If you're using F#, you can parse F# script files and include your documentation right alongside your code. The F# Formatting project also provides hover tips for F#. Let's look at an example F# script file. You can see the full file in Listing 1 and the output in Figure 3.

Listing 1: Example F# Formatting script contained in an F# Script file. Documentation works side by side with code.

(**
Partial Application
===============
Here's an example of partial application.

This function is the Minkowski distance. Then, I use
partial application to create the Manhattan distance
and the Euclidean distance from the Minkowski distance.
*)

(*** include: Minkowski ***)

(** where `list_difference` is defined as: *)

let list_difference = List.map2 (fun x y -> x - y)

(*** define: Minkowski ***)
/// Minkowski distance = (SUM (| x ? y |^p) )^(1/p)
let minkowski p list1 list2 =
    let abs_powered p (x:float) = abs x ** p
    let distance =
        list_difference list1 list2
            |> List.map (abs_powered p)
            |> List.sum
    distance ** (1.0/p)

/// Manhattan distance = SUM(| x - y |)
let manhattan = minkowski 1.0

/// Euclidean distance = SQRT ( SUM(| x - y |^2) )
let euclidean = minkowski 2.0
Figure 3:  Using F# Formatting to generate documentation
Figure 3: Using F# Formatting to generate documentation

First, you can use standard markup to create headings, change font styles, or add links, so here I'm just creating a heading for the page, and adding some up-front text about what should come next.

(**
Partial Application
===============
Here's an example of partial application.
This function is the Minkowski distance.
Then, I use partial application to create the
Manhattan distance and the Euclidean distance
from the Minkowski distance. *)

Let's skip to the end of the example and look at some simple code next. This is basic code. I'm simply defining two functions, Manhattan and Euclidean. There's no need to add tags or tell the program that you've written code. The parsers just know. Adding comments using a triple slash, as is standard, provides the description to the tooltips for that function. See Figure 4 for an example.

/// Manhattan distance =
/// SUM(| x - y |) 
let manhattan = minkowski 1.0

/// Euclidean distance =
/// SQRT ( SUM(| x - y |^2) )
let euclidean = minkowski 2.0

Now, here's a fun example. Sometimes, with documentation, it doesn't make sense to discuss the code in strict order, but for the tooltips to show up correctly, it's important to have all the code in the file in the correct order. In this next snippet, I use include and define to reorganize how the code should read.

Figure 4: Using a triple-slash ensures that information is included in tooltips on your docs.
Figure 4: Using a triple-slash ensures that information is included in tooltips on your docs.

I want to first discuss a code snippet, the longer Minkowski function, and define one of the functions that it relies upon later. I use define above the Minkowski function. Then, I can use include wherever I'd like the function to be placed in the documentation. Finally, I display the list_difference function after the include section but before the define section, using back ticks to make sure that the name of the function correctly stands out. Using this trick, I can make sure that the tooltips correctly display, as in Figure 5.

(*** include: Minkowski ***)

(** where `list_difference` is defined as: *)
let list_difference = List.map2 (fun x y -> x - y)

(*** define: Minkowski ***)
/// Minkowski distance =
/// (SUM (| x ? y |^p) )^(1/p)
let minkowski p list1 list2 =
    let abs_powered p (x:float) =
        abs x ** p     
        let distance = 
            list_difference list1 list2
              |> List.map (abs_powered p)
              |> List.sum
        distance ** (1.0/p)

Note that I can add text comments at any point in and around the code for clarification.

Figure 5: Correct Tooltips
Figure 5: Correct Tooltips

FAKE

Next, let's check out FAKE. FAKE is a robust build-automation tool, similar to MAKE and RAKE, that uses the concept of targets to break apart the many pieces of a build process into more tangible chunks. Targets require a name and an action, and can be linked together.

Let's look at a sample FAKE script file to understand them better. You start by referencing and opening the FAKE library. Then there are two targets, Test and Build. Within the lambda function, you define what work they should do. Finally, you need to declare that Test depends upon Build.

#r "tools/FAKE/tools/FakeLib.dll"
open Fake

Target "Test" (fun _ ->
// Run some tests
)

Target "Build" (fun _ ->
// Build project
)

"Build"
==> "Test"

Let's look at a more complicated target now. For example, it's possible to run your tests as part of the build by creating a RunTests target. This starts by finding the test assemblies, which I'll look at in more detail in a moment, and passing it to the included NUnit function along with a set of parameters. In this case, I'm sending:

  • DisableShadowCopy = true, which disables shadow copying of the assembly. This improves performance.
  • TimeOut = TimeSpan.FromMinutes 20, which times out test running 20 minutes after starting.
  • OutputFile = “TestResults.xml”, which specifies where the output file should be.
Target "RunTests" (fun _ ->
    !! "/.test/NUnit.Test.*.dll"
    |> NUnit (fun p ->
        { p with
            DisableShadowCopy = true
            TimeOut = TimeSpan.FromMinutes 20
            OutputFile = "TestResults.xml" })
)

Now, let's look a little closer at how to find the test assemblies. FAKE uses its own globbing syntax. It's closely related to the syntax used in .gitignore files, but does differ in a few places and includes several operators. First, the !! before the value means to include and scan all files matching the following pattern. In this case, the pattern is fairly simple. In the .test directory, search for all files that end in .dll, and start with NUnit.Test.

Here, I'm recursively searching in the tests directory for all bin subdirectories. Then, depending on whether the configuration value is set to Debug or Release, I look in only the appropriate directory. This is flanked by </>, which adds a “/” to either side and preserves the path. Finally, I'm looking for items that contain the word “Tests” and end in .dll. Like this:

"tests/**/bin" </>
    configuration </>
    "*Tests*.dll"

It's also possible to automatically run your FxCop rules, create a NuGet package, or integrate Chocolatey, Slack, TeamCity, Canopy, and many other programs. Check out the FAKE documentation for more information on these.

It's also possible to automatically run your FxCop rules, create a NuGet package, or integrate Chocolatey, Slack, TeamCity, Canopy, and many other programs.

Using Paket with FAKE to Restore Packages at Build Time

Using Paket and FAKE together to restore packages at build time is usually done in a separate batch file as part of the set-up process. Let's go through an example file. First, you need a couple of standard commands. It's very common at the top of batch files to include the command. Ordinarily a script echoes the commands that it runs, and echo off turns that off. And by adding the @ at the beginning of the command, command echoing is turned off, and the request to turn off command echoing is turned off.

Next, there's a call to cls, which clears the screen.

@echo off
cls

Next, there's a check to see that the Paket executable exists. If it doesn't, the Paket bootstrapper should be run. This causes the latest version of the executable to be downloaded and installed.

IF NOT EXIST .paket\paket.exe (
    .paket\paket.bootstrapper.exe
)

Next, there?s a call to Paket restore to restore the packages.

.paket\paket.exe restore

If the previous statement returned any errors, you should exit. In general, successful code returns 0, and errors can be anything non-zero. In general, they're positive, but not always. The if errorlevel 1 construct has a fun little feature though: it checks whether the error code is anything larger than 1. In this case, I happen to know that Paket doesn't contain negative error numbers, so it's safe to only check positive non-zero numbers.

if errorlevel 1 (
exit /b %errorlevel%
)

Next, run a Paket update:

.paket\paket.exe update

Finally, you'll need a call to FAKE, sending the build.fsx file and any other arguments from the command line.

packages\FAKE\FAKE.exe build.fsx %*

Putting this all together, you can see the script in full.

@echo off
Cls

IF NOT EXIST .paket\paket.exe (
    .paket\paket.bootstrapper.exe
)

.paket\paket.exe restore

if errorlevel 1 (
    exit /b %errorlevel%
)

.paket\paket.exe update

packages\FAKE\FAKE.exe build.fsx %*

More Information

For more information about using the three projects together, I recommend checking out the Project Scaffold repository: http://fsprojects.github.io/ProjectScaffold/. This project sets up FAKE to build documentation and create a NuGet package, as well as a few other useful examples.