API Design: In The Wild (part 2)
Tags: programming, codequality, coding
Published: 2019-05-19 14:37:09

---
title: API Design: In The Wild (part 2)
published: true
tags: [programming, codequality, coding]
canonical_url: http://samwho.dev/blog/2019/05/19/api-design-in-the-wild-part-2/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/y6dgh0ks84zk1z7ehqkj.png
series: API Design
---

In a previous post we looked at some real-world APIs, highlighting the good and the bad, and in this post we’re going to do the same!

- Python’s `datetime.datetime`
- Java’s `URL.equals` method
- Go’s standard library
- The word “filter”
- Conclusion

## Python’s `datetime.datetime`

Most experienced Pythonistas have written something like this at some point in their career:

```python
import datetime
now = datetime.datetime.now()
print(now)
```

While not incorrect, the repeated naming is jarring.

Go specifically calls this out in a blog post on [package naming](https://blog.golang.org/package-names), and I don’t think I could possibly improve on it so I’ll quote it verbatim:

> **Avoid stutter.** Since client code uses the package name as a prefix when referring to the package contents, the names for those contents need not repeat the package name. The HTTP server provided by the `http` package is called `Server`, not `HTTPServer`. Client code refers to this type as `http.Server`, so there is no ambiguity.

You can combat the stuttering somewhat using Python’s `from x import y` syntax:

```python
from datetime import datetime
now = datetime.now()
print(now)
```

As a fun little extra, a friend sent me the following bit of Ruby:

```ruby
files = Dir.entries(Dir.pwd)
files.select! { |file| File.file?(file) }
```

![Finding Nemo "Mine" meme but using "file" instead](http://samwho.dev/images/file-file-file-file-file.gif)

## Java’s `URL.equals` method

If you were going to test two URLs for equality, how might you do it?

It’s completely reasonable to do a comparison of the string representations. `”https://google.com” != “https://facebook.com”`. This isn’t the road the original authors of Java’s `URL` class took, though.

```java
import java.net.URL;

public final class Main {
	public static void main(String... args) throws Exception {
		URL a = new URL("https://google.com");
		URL b = new URL("https://google.com");
		System.out.println(a.equals(b));
	}
}
```

Does this always return true?

Sadly not.

`java.net.URL.equals`, through a long chain of indirection, ends up calling `java.net.InetAddress.getByName` for both of the URLs, which performs a DNS lookup in order to check that they resolve to the same IP address. It does have a cache, but if you’re super unlucky and the cache expires between the two lookups, it’s possible for you to get two different IP addresses for the same hostname if that hostname uses DNS round robin, which is common in 2019.

Similar to `java.io.File.exists`, this method doesn’t quite do what it advertises to do. Because of this, and the fact it makes a blocking network call, it’s [flagged by static analysis tools](http://errorprone.info/bugpattern/URLEqualsHashCode).

## Go’s standard library

I hesitated to add this section, as it’s fairly controversial, but I do think there’s a real problem here.

Go’s standard library is missing some key things I’d expect to find in a standard library. The desire to keep the language implementation and usage simple has shifted burden from the language implementor to the language user.

For example, checking that a list has a specific element is not something the language provides for you. If you were to [look it up](https://stackoverflow.com/a/10485970), the attitude you find is that methods like this are trivial to write. While true, I find myself frequently looking up and copy-pasting trivial methods on a weekly basis.

Efforts to add common operations to the standard library are appreciated, but often clunky. Getting an [absolute value](https://golang.org/pkg/math/#Abs) requires you to cast to and from a `float64`. [Sorting an array](https://golang.org/pkg/sort/#Slice) requires you to sacrifice type safety and supply your own swapping function. [Creating a big int](https://golang.org/pkg/math/big/#Int.SetInt64) has a method per type that you can create them from, appending the type to the method name.

The addition of generics and method overloading, while complicating the language and its implementation, would make life easier for users of the language.

## The word “filter”

How would you define the word “filter” in general use? Most people, myself included, thinking of removing things. Impurities from metal, dirt from gold, water from pasta.

So what does this return?

```python
list(filter(lambda n: n > 5, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
```

If you guessed “a list containing all numbers greater than 5”, you would be correct.

I find this confusing. I have to check which way `filter` works almost every time I use it, even though in the research I did for this post I learned that `filter` works the same way in every language I checked.

I like the approach Ruby takes to this problem:

```ruby
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list.select { |n| n > 5 } # [7, 8, 8, 9]
list.reject { |n| n <= 5 } # [0, 1, 2, 3, 4, 5]
```

`select` and `reject` are more immediately obvious, and good general words for these use cases. At least they’re better than [`filterfalse`](https://docs.python.org/3/library/itertools.html#itertools.filterfalse).

## Conclusion

Another post, another set of real-world API examples and suggestions on improving them.

I’d love to hear your thoughts, and if you have any APIs you love or hate I’d love to hear about them as well!