PurelyFunctional.tv Newsletter 341: Tip: tidy up your ns form

Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.

Issue 341 - August 26, 2019 ยท Archives ยท Subscribe

Clojure Tip ๐Ÿ’ก

keep your ns declaration tidy

We've all done it at some point. We're really rolling on a new project and we're itching to import a new library. So we copy and paste from the example in the README and paste it right into our code.

After a few hours, the top of our file looks like this:

(ns my-project.core
       (:use some-library)
       (:use another-library)
  (:require [clojure.string :refer [upper-case lower-case])
  (:require [clojure.java.io :as io]
                 [foo.bar :refer [baz
                                        ;; cux
                  ]])))

(use 'favorite-lib.core)

(require 'lib4clj.core)

(import 'java.util.Date)

It's a mess! It's hard to see what's been imported, and it will slow you down. (Also: there's a bug in there that would be way easier to spot with some tidying.)

But what's worse is the impression it makes on others. If you're looking for a job and you send someone this code, here is what is going through their mind: "Oh, no! This person has never worked on a serious project."

At least that's the strong impression it gives me. If you want to make a good impression, clean that up. Cleaning it up will exercise your code movement skills. You will be moving a lot of code once you get the job. It also shows respect for the person who will be reading the code.

Here's what the above code looks like when it's neat and tidy:

(ns my-project.core
  (:require [some-library :refer :all]
            [another-library :refer :all]
            [clojure.string :refer [upper-case lower-case]]
            [clojure.java.io :as io]
            [foo.bar :refer [baz]]
            [favorite-lib.core :refer :all]
            [lib4clj.core])
  (:import java.util.Date))

It's much easier to read and gives a more organized impression. However, I would go further. I converted use into require with :refer :all. This is usually not ideal if you're doing it to a lot of namespaces. You should choose a namespace alias and use it instead.

(ns my-project.core
  (:require [some-library      :as sl]
            [another-library   :as al]
            [clojure.string    :as str]
            [clojure.java.io   :as io]
            [foo.bar           :refer [baz]]
            [favorite-lib.core :as fl]
            [lib4clj.core      :as lib4clj])
  (:import java.util.Date))

Woah! Clean as a whistle and easy on the eyes.

Here are some recommendations for squeaky-clean ns declarations:

  1. Put all dependencies into the ns. No exceptions.
  2. Don't use :use. In general, people recommend against it. If you need similar functionality, use :require with :refer :all. But see #3.
  3. Avoid :refer :all unless you have a good reason. Laziness is not a good reason. A good reason is that it is a well-known library whose functions are named to help you know where they came from. An example is clojure.test inside of a testing namespace.
  4. Give your namespaces short, descriptive aliases. Abbreviation is good. Use well-known aliases for common libraries, like str for clojure.string.
  5. Don't :refer too many names. A handful is okay.
  6. Use good whitespace. New lines are important. Alignment can help readability. Keep it indented correctly.

Are there any guidelines you follow? Hit reply and let me know.

Book status ๐Ÿ“–

My book is out! You can buy the book now in early access. The first three chapters are available and you'll get updates as new chapters come out.

Grokking Simplicity teaches functional programming in a friendly way, to those who are not familiar with it or who were turned off by the overly academic resources.

You can get 50% off the normal prices with discount code MLNORMAND. It will work until August 31, so don't delay. I don't really control the sales and discounts, so I don't know when the next one will be.

Also, there's no "look inside" on my book, so I'll share some images of pages here. Click the picture to see a bigger version.

Retraction โŒ

I regret describing The Bell Curve as a "racist, pseudoscientific screed". Last week I mentioned the book in the context of Apollo: The race to the moon.

The Bell Curve is indeed a controversial book. I was told about it in High School by a teacher who said it was racist. I never read it myself. I simply parroted what he taught me to you in this newsletter. You deserve better than repeated hearsay.

A couple of readers disagreed with my words. I looked into it and I realized my mistake. I know nothing about the book, and very little about the controversy around it. I'm not defending the book nor am I supporting it. But I should not have used such strong language about a topic I know nothing of. If the topic interests you, please form your own opinions.

I am grateful that you put your trust in me to have my newsletter in your inbox every week. I betrayed that trust by speaking out of turn. I apologize.

Conference alert ๐Ÿšจ

Clojure/conj CFP and Opportunity Grant applications are due soon. The conference is in November in Durham, NC.

Currently recording ๐ŸŽฅ

I am now recording a course called Property-Based Testing with test.check. Property-based testing (PBT) is a powerful tool for generating tests instead of writing them. You'll love the way PBT makes you think about your system. And you can buy it now in Early Access. Of course, PF.tv members have had access since the beginning, along with all of the other courses.

New lessons this week include:

  1. Testing pure functions --- Pure functions are the easiest to test, so that's where we start. We test three fairly mathematical functions (reverse, sum, and min). We look for complete coverage of the behavior by trying to find an incorrect implementation that could pass the tests. Then we test two real-world functions I snagged from some real projects. These are a little more involved since we need to create custom generators for them. All the better to learn from!
  2. Testing stateful systems --- Once you bring in mutable state, the complexity of your system skyrockets. Now you have to deal with actions performed in arbitrary order. We look at two examples of stateful systems and how to test them. Testing mutable state is where Property-Based Testing really starts to shine. We essentially test every part of the interface in hundreds of combinations.

I've made the first and fifth lessons free to watch. Go check them out.

Members already have access to the lessons. The Early Access Program is open. If you buy now, you will get the already published material and everything else that comes out at a serious discount. There are already 9 hours of video, and looking at my plan, this one might be 12 hours. But that's just an estimate. It could be more or less. The uncertainty about it is why there's such a discount for the Early Access Program.

Brain skill ๐Ÿ˜Ž

focus

We can often learn better in long periods of focus. Learning means challenging your brain. That can be uncomfortable. Your brain will rebel and seek out distractions. Often the most uncomfortable part is right at the beginning. Being able to focus means sticking with it long enough to get over the initial hurdle.

Focus also helps you keep more stuff in your head at once. Our attention is very limited. A distracting noise or idea could bump out the hour of work you've done to load a difficult concept into your head. Being able to focus means eliminating those distractions so you can work with the idea efficiently.

This guide from Scott Young has useful tips for increasing your ability to focus.

Clojure Challenge ๐Ÿค”

Last week's challenge

The puzzle in Issue 340 was to write a simplifier for the symbolic differentiator we did the week before.

You can check out the submissions here.

This week's challenge

permutations of a sequence

The permutations of a sequence are all of the sequences with the same elements but in different orders. Here are some examples.

The permutations of [1, 2] are [1, 2] and [2, 1].

The permutations of [1, 2, 3] are [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], and [3, 2, 1].

The number of permutations grows really fast with the size of the list.

Your challenge is to write a function that generates all permutations of a list. Your function should return a lazy sequence.

Note: there already is a great, fast implementation of this function in clojure.math.combinatorics

As usual, please send me your implementations. I'll share them all in next week's issue. If you send me one, but you don't want me to share it publicly, please let me know.

Rock on!
Eric Normand