Good point; let's split out the tile computation in distarray:

```
def good_tile_shape(shape, tile_hint, num_shards):
  splits = [None] * len(shape)                                                                                                                                 
  if tile_hint is None:
    if num_shards != -1:
      tile_size = np.prod(shape) / num_shards
    else:
      tile_size = DEFAULT_TILE_SIZE

  # fill up dimensions...
  tile_shape = [1] * len(shape)
  idx = len(shape) - 1
  while tile_size > 1:
    tile_shape[idx] = max(shape[idx], tile_size)
    tile_size /= shape[idx]

  return tile_shape
```