RackConnect v3.0 load balancer add/remove steps

This adds `IStep` implementations to `otter.convergence` for adding nodes to and removing them from RackConnect v3.0.

Furthermore, it generalized the optimizer step that @radix added to easily be extensible for multiple classes. Maybe one day we'll have to do multi-pass optimization; today is not that day :smile:

There are some `REVIEW` comments inline.

RCv3 supports bulk add/delete steps that allow adding or deleting any combination of nodes and servers in a single request, e.g. the following server, LB pairs can all be added and removed within a single request:

```clojure
[[:a :A]
 [:a :B]
 [:b :B]
 [:c :B]
 [:d :D]]
```

It stands to reason we'd want to use those requests, so that's what the optimizer produces. However, CLB does not support the same "n x n" API. In order to make this future-proof, I've added steps that mimic CLB's API. That way, the convergence code that produces load balancer steps doesn't have to care an awful lot whether it's working with RCv3 or CLB. The optimizer step is repsonsible for turning the intent specified by those steps into the most optimal representation as HTTP requests.
it occurs to me that dropping AddNodesToRCv3LoadBalancer (singular) and only using the plural would solve a few problems:

- this case you mention would be handled
- you wouldn't need the NotImplementedError
- it'd be less code
- it'd be consistent with AddNodesToLoadBalancers