To test or not to test. How to write less unit tests and keep quality.

We need unit tests to avoid regressions and to write less code during implementation (TDD). But I’m still looking for a better ways of testing, how to reduce number of tests but keep good quality of product, how to make them less fragile and more valuable.

Some part of problems we have comes from tools we use. If you switch from object oriented programming to functional programming lots of problems just dapperer and testing become much simpler

Today I would like to recommend two articles saying where to concentrate your testing efforts and how to do it better.
Selective Unit Testing – Costs and Benefits
Test-induced design damage or why TDD is so painful

You should focus on testing your business logic, algorithms. Recommended way is to do it on level of aggregates. You can skip simple code with cyclomatic complexity equal 1. Testing of coordination code which often contains high number of dependencies generates lots of fragile and low-value tests. If you have code which mix logic and coordination – refactor it. Separate logic from coordination.

Reklamy
To test or not to test. How to write less unit tests and keep quality.

Compile F# library to JavaScript library with Fable, Babel and Webpack

I have a F# library with business logic. It is build from few F# projects referenced together without any third party assemblies. I have complete source code of it. And my goal is to compile it to javascript library, so it can be used on node platform.

Because it is build from few projects I need to define which functions will be exposed as an API of this library. The best way will be define new project. I will put there also all compilation configuration (BTW I’m doing this on linux with dotnet core and node installed).

1.Create new folder and enter to it

mkdir api
cd api

2. Create new dotnet core F# project (I’ve specified also target framework)

dotnet new classlib -lang F# -f netcoreapp2.1

3. Create new javascript project in the same folder

yarn init

4. Edit package.json, add scripts to run compilation and development dependencies

{
"name": "api",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",

"scripts": {
"compile": "webpack",
"watch": "webpack -w",
"build": "webpack -p"
},
"devDependencies": {
"@babel/core": "^7.2.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/preset-env": "^7.2.0",
"babel-loader": "^8.0.4",
"fable-compiler": "^2.1.6",
"fable-loader": "^2.1.0",
"webpack": "^4.27.1",
"webpack-cli": "^3.1.2"

}
}

I’ve added dependencies to webpack which will bundle all files, babel to transpile to older javascript and fable to compile F# to javascript. Additional babel plugin is to get nicer babel output.

Script commands are:
compile – generates debug version,
watch – like compile but repeats automatically after every file save,
build – generates release version

5. Everything will be run through webpack, so I need to configure it. Create in current folder webpack.config.js file:

var path = require("path");
var webpack = require("webpack");

function resolve(filePath) {
return path.join(__dirname, filePath)
}

var babelOptions = {
presets: ["@babel/env"],
plugins: ["@babel/plugin-transform-modules-commonjs"]
};

var isProduction = process.argv.indexOf("-p") >= 0;
console.log("Bundling for " + (isProduction ? "production" : "development") + "…");

module.exports = {
mode: isProduction ? 'production' : 'development',
devtool: "source-map",
entry: resolve('./project.fsproj'),
output: {
filename: 'bundle.js',
path: resolve('./dist'),
library: "lib",
libraryTarget: "commonjs2"
},
resolve: {
modules: [ "node_modules", resolve("./node_modules/") ]
},
module: {
rules: [
{
test: /.fs(x|proj)?$/,
use: {
loader: "fable-loader",
options: {
babel: babelOptions,
define: isProduction ? [] : ["DEBUG"]
}
}
},
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: babelOptions
}
}
]
}
}

On the beginning I have utilities to resolve paths, babel configuration, checking if this is production or development (debug/release) and then goes webpack configuration. Change ‚entry’ to your project name and output as required (currently is ./dist/bundle.js). At the end I have configuration of two file loaders. Generally fable-loader gets *.fs files from project, sends to fable -> babel -> webpack. Babel-loader searches for additional javascript files and send them to babel and then to webpack.

6. Now I can check if this is working. Install dependencies listed in package.json

yarn install

7. Compile/transpile project

yarn run compile

8. I can go to dist folder and check what have been exported (there should be single hello function generated by dotnet in Library.fs file) and run it.

cd dist
node
var lib = require('./bundle');
console.log(Object.keys(lib));
lib.hello('abc');

9. Now I can reference my real F# project and define API for it (only last fs file in project will be exposed as javascript api, so I will keep only single file in this project). In project.fsproj I add reference:

  <ItemGroup>
<ProjectReference Include="../OtherProject/other.fsproj" />
</ItemGroup>

10. Define library API in Library.fs (single fs file generated by dotnet in this project)

module MyProject.MyModule
open OtherNamespace.OtherModule

let myApiFuncToExposeInJS = funcFromOtherModule

This is it, working javascript library from F#

Compile F# library to JavaScript library with Fable, Babel and Webpack

F# 4.1 / .netcore 2.0 on AWS Lambda

I’ve started with installing serverless on node and configuring it.

npm install -g serverless

then we have to configure credentials. You need aws account with IAM user with admin rights. Here is a short guide how to do it. When we have account keys we can configure credentials.

serverless config credentials --provider aws --key XXXXXX --secret XXXXXXX

it will create „.aws” folder in your home directory with credentials.

Then I’ve installed dotnetcore.  I’m using current linux mint 18.03 based on ubuntu 16.04.

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list'

sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-2.1.101

Installing separate fsharp is not required but I want to have REPL. Apt will find it in Microsoft repository or as suggested on fsharp.org we can connect mono repository.
But from unknown reason from Microsoft repository I get older version. So I connect mono repository.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
echo "deb http://download.mono-project.com/repo/ubuntu stable-xenial main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
sudo apt-get update

sudo apt-get install fsharp

We can verify installed versions

mono --version
dotnet --version
fsharpi

To create aws project we use serverless (in empty folder, or we can use –path and specify folder)

sls create --template aws-fsharp

Unfortunately it’s still creating .netcore 1.0 version, so I had to update it manually, but it was quite fast. Probably next version of serverless will be working with dotnetcore 2.0. You can find upgraded sample on my GitHub.

We execute build script „build.sh” and deploy it to amazon (add execution rights to build.sh). Then we can invoke our test function „hello”.

sls deploy
sls invoke -f hello --data '{"Data": "some data"}'

To remove all your project resources from aws call

sls remove
F# 4.1 / .netcore 2.0 on AWS Lambda

Using curl in powershell

Remove curl alias

By default in power shell 5.x command curl is an alias for Invoke-WebRequest, so it’s not real curl. To replace it first I needed to remove an alias.

To change aliases a profile for powershell is required, it can be created with command:

New-Item $profile -force -itemtype file

to edit it run:

notepad $profile

then add alias remove instruction to file and save it

remove-item alias:curl

repeat last instruction in command line or reopen powershell to read it from profile.

Install real curl

I will install curl from chocolate package (https://chocolatey.org/). On chocolatey site are all information how to install from powershell (you need administrator mode). When you have it run:

choco install curl

Now you can start using curl.

Using curl in powershell

Discriminated union in C# with type safety

I’ve been updating some methods which returns as result small class. This class contains all success data and also all failure data. Small part is shared in both cases but mostly only part information is filed depending on a case. And I thought, what a shame I don’t have discriminated union in C#, perfect solution in such case. As a regular developer I’ve checked stackoverflow and there it was, excellent implementation with type checking at compilation time.

public abstract class ResultUnion<S, F>
{
   public abstract T Match(Func<S, T> fs, Func<F, T> ff);

   private ResultUnion() { }

   public sealed class Success : ResultUnion<S, F>
   {
      public readonly S Value;
      public Success(S value) { Value = value; }
      public override T Match(Func<S, T> fs, Func<F, T> ff) => fs(Value);
   }

   public sealed class Fail : ResultUnion<S, F>
   {
      public readonly F Value;
      public Fail(F value) { Value = value; }
      public override T Match(Func<S, T> fs, Func<F, T> ff) => ff(Value);
   }
}

and the example usage:

var result = new ResultUnion<int, string>.Success(0);
or
var result = new ResultUnion<int, string>.Fail("error");

Console.WriteLine(
   result.Match(
     sVal => sVal.ToString(),
     fVal => fVal
   )
);
Discriminated union in C# with type safety