The real trick is doing both. Code that reads like a short story while including error handling and edge cases. This is achieved in a practical way by first keeping it as simple as possible only implementing strictly necessary abstractions. When the code reaches a "tipping point" then refactor. Rinse and repeat. If the code is structured reasonably that refactor should be mostly limited to the trouble spot.