Refactor SlotKeys to be a separate class

The string `SlotKey` is a 3-tuple `(granularity, slot, shard)` and passed around as a string. whenever we need to decompose the tuple, we manually parse it.

Instead of doing that, a new class `SlotKey` is introduced to carry around this data. We do the validation when construct the object, thus the code becomes much more reliable. Another benefit is that it's easy to trace where this `SlotKey` type is used throughout the code.

I also removed various methods in `Granularity` class since most of them are obsolete - they simply become the getter. I also removed `locatorKeys` function because I would've had to refactor it, but it's not being used anywhere throughout the code.
curious about why you chose this change?