One really simple solution that may help could be to look at one of the reasons cities were contained in ancient times. City walls. I'm not suggesting that there necessarily be a cost in materials applied to snaked cities, but it could be used to apply a defensive factor.
The number of sides exposed from each tile could be used to provide a variable that is applied as one of the defensive factors to units defending a city.
Lets say that a perfectly formed (square) city provides a base defense factor of 3 and a worst-case (diagonal) city provides a base defence factor of 1 then cities would exist somewhere along the continuum.
max_factor = 3;
i = ceil(sqr_root(num_tiles)); // get max tiles to form square
min_sides = i x 4; // get number of sides if square
max_sides = i^2 x 4; // get number of sides if laid out diagonally
def_factor = (max_sides x max_factor)/(actual_sides x i);
So as an example
A city has 14 tiles but is layed out so that 18 sides are shown...
max_factor = 3;
i = ceil(sqr_root(14)) = 4
min_sides = 4 x 4 = 16
max_sides = 4^2 x 4 = 64
def_factor = (64 x 3)/(18 x 4) = 192/72 = 2.7
So a unit with a base defence of say 8 would have this boosted to 21 (8 x 2.7). If the city was perfectly formed it would have a defence of 24 (8 x 3). Pretty compelling reason to lay out defensive cities in a contained manner.
City improvements could then also be used to boost the max_factor variable. Eg. Hedge wall make max_factor increase to 4. etc et.