Sculpt Your Code in a REPL - Part Two

Welcome back

In the last post we meandered down the REPL path and wound up wanting to create something that would encourage experimentating with code in a REPL and providing us with feedback so we ended up with sculpted code and not a lump of clay.

Hopefully you had some time to think about how you would solve the problem. I had fun coming up with my solution but it's just one attempt at it. Without further ado let's see what a tool for experimenting in the REPL could look like.

Defining the experiment

The experiment I want to attempt today is partly practical since it could come in handy for future blog posts. I want to take a blog post title and convert it into part of the url for the post. You may have heard of it as a url slug. There are plenty of examples out there of making robust url slugs even ones that account for non-English language. The slug generator in this example is definitely not production worthy so don't take this one to production and we'll both be happy.

Let's start by defining our experiment. A simple title should work to identify our experiment and make it clear what we are trying to accomplish. The next part is the most important part - the hypothesis. This is the thing we are trying to prove or disprove. In this case a simple declarative statement like "A blog title can be converted into a valid url" should work. Feel free to make your hypothesis more descriptive or longer. This seems like a good time to document the assumptions that I want to make for the rest of my experiment. When it comes to slugifying something into a url the main assumptions I need for this experiment are that I can determine if a url is valid or not. Without those assumptions being true my examples probably won't work since I won't have any reasonable way to validate the results of the experiment.

experiment "Convert a blog post title into a valid url slug" (fun _ ->

    hypothesis "A blog title can be converted into a valid url"

    assumption "I can determine when a url is invalid" (fun _ ->
        expect (("something??/hello there" |> isWellFormedRelativeUri) = false)
    )

    assumption "I can determine when a url is valid" (fun _ ->
        expect (("something??/hello-there" |> isWellFormedRelativeUri))
    )

)

Creating the examples that test the hypothesis

Now that we have the outline of the experiment and the assumptions that ensure we can test our results let's come up with the experiment examples or steps that fill out the experiment and make it more rigorous. You could build these examples out one at a time creating more and more complex scenarios or you could try to define them all at once. I like the first method as it let's me focus on writing just enough code to make the example work.

experiment "Convert a blog into a valid url" (fun _ ->

    hypothesis "A blog title can be converted into a valid url"

    assumption "I can determine when a url is invalid" (fun _ ->
        expect (("something??/hello there" |> isWellFormedRelativeUri) = false)
    )

    assumption "I can determine when a url is valid" (fun _ ->
        expect (("something??/hello-there" |> isWellFormedRelativeUri))
    )

    example "Simple one word title" (fun _ ->
        let slug = toSlug "demo"

        expect ("demo" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Capitalized one word title" (fun _ ->
        let slug = toSlug "Demo"

        expect ("demo" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Phrase as a title" (fun _ ->
        let slug = toSlug "This post is amazing"

        expect ("this-post-is-amazing" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Phrase as a title with dashes" (fun _ ->
        let slug = toSlug "This post is amazing - No Joke"

        expect ("this-post-is-amazing-no-joke" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )
)

The REPL friendlyness is in the way this code can be used. You can select and run individual examples or the run the entire expermient. The simple string and function pattern is straight-forward and works as expected. The API tries to be simple and declarative so it stays out of your way and you can think about the problem you are trying to solve and not trying to remember what attribute is needed to get the test runner to see your code. I opted for a simpler "expect" instead of getting into the test framework asserts and comparisons since F# has the expressiveness I was after for this simple experiment.

Concluding the experiment

A good experiment is one where findings are documented so they can be compared and shared with others (and so the scientist doesn't forget what the results were). To accomplish that we'll add a findings section where we can document the conclusions we drew from this experiment.

experiment "Convert a blog into a valid url" (fun _ ->

    hypothesis "A blog title can be converted into a valid url"

    assumption "I can determine when a url is invalid" (fun _ ->
        expect (("something??/hello there" |> isWellFormedRelativeUri) = false)
    )

    assumption "I can determine when a url is valid" (fun _ ->
        expect (("something??/hello-there" |> isWellFormedRelativeUri))
    )

    example "Simple one word title" (fun _ ->
        let slug = toSlug "demo"

        expect ("demo" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Capitalized one word title" (fun _ ->
        let slug = toSlug "Demo"

        expect ("demo" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Phrase as a title" (fun _ ->
        let slug = toSlug "This post is amazing"

        expect ("this-post-is-amazing" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    example "Phrase as a title with dashes" (fun _ ->
        let slug = toSlug "This post is amazing - No Joke"

        expect ("this-post-is-amazing-no-joke" = slug)
        expect (slug |> isWellFormedRelativeUri)
    )

    findings "Creating a url slug from a title is possible! While this method does not account for UTF-8 encodings or foreign languages it solves the cases we were after."
)

Experiment output

Running this experiment in the REPL gives us the following output:

Conducting Experiment) Convert a blog into a valid url

    Hypothesis: A blog title can be converted into a valid url

        Assumption) I can determine when a url is invalid - VALID

        Assumption) I can determine when a url is valid - VALID

        Example) Simple one word title - PASSED

        Example) Capitalized one word title - PASSED

        Example) Phrase as a title - PASSED

        Example) Phrase as a title with dashes - PASSED

Findings) Creating a url slug from a title is possible! While this method does not account for UTF-8 encodings or foreign languages it solves the cases we were after.

The experiment (Convert a blog into a valid url) has concluded successfully. Huzzah!

This gives us feedback similar to TDD in that we know when something passes or fails and we can adjust accordingly. Now that things are working and our experiment is providing valid results let's talk about how to get the most value out of this simple tool.

When not to use this code

The uses for this framework go beyond a single person experimenting with code and abstractions in the REPL. Before we get into what it can be used for let's go over what it's not intended for.

Usage as a TDD framework for production code

This is not meant to be a fully featured TDD framework. It will not hook into a test runner and it does not have a TeamCity plugin. If you try and use this for production code testing you may not be happy with the results and I make no claims that it will work.

Now let's brainstorm what you could use it for.

Suggested usage

The code is pretty free form and it's up to you and your imagination to come up with uses for it. Here are some of the potential uses I came up with:

Findings

This was a fun experiment for me. I was able to throw together a simple API for experimenting in the REPL and provide feedback so the code I wrote was sculpted and formed by the immediate usage. I can't claim that either the toSlug function or the experiment API are THE SOLUTION but they are a solution that solves my immediate problem and provides room for growth.

So...how does this stack up to what you came up with? Did you have all sorts of whiz-bang features that would knock someone off their chair? Whether you thnk your solution is amazing or not share it in the comments. I have another post coming soon that will take the experiment idea a little further and look at how we could extend it to be more useful. Stay tuned and happy experimenting!

Further resources

The code for the experiment API can be found here.
The code for the slug experiment using the F# interactive window can be found here.
To prove that I'm not some F# snob I created a wrapper for C# so you can compile the experiment API into a dll and use it from LinqPad or scriptcs. The code for the experiment converted to C# can be found here.



Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© 2017 Frank Meola

Back to top