I'm mostly writing this for myself. These are some of the topics I keep coming back to, these questions are stuck in my head like a earworm.
Whenever I'm stuck, re-contextualising the problem always gives me a fresh perspective and lets me make progress. The ability to look at a problem from a different point of view is a very powerful tool — this post is an attempt to list down some 'recipes' for this.
Examples
I'm contrasting two approaches or perspectives that can typically be applied to the same problem. I'm not advocating doing one or the other, I feel that it's often crucial to use both approaches simultaneously.
Flowcharts vs State diagrams
Flowchart (or any diagram where we're thinking about sequential ordering) and state diagrams (which are more about the 'possibility' space) are both indispensable tools when building any system.
Both serve very different roles, but I've found that being able to switch from one mental model to another is very valuable when building anything complex.
Line charts vs Histograms
On a very related note, looking at a histogram gives you a radically different perspective than looking at a line chart.
Taking the same data set, just changing the way you look at it will give you completely different insights.
Code vs Data
Code vs Data is one of the most fundamental questions you can ask when writing code (unless it's lisp).
Examples: converting complex logic into a decision table, passing functions around, or creating 'encapsulated' functions that are partially applied.
Aggregate vs Individual
When designing any system, or analysing the behaviour of any system, think about both aggregate behaviour (eg: median response times, error rates) vs the behaviour of individual requests (step through the entire call tree).
Both give you different perspectives. Both are crucial.
Also important: aggregates might hide issues that consistently occur for a subset of users. Your error rate may be 0.001% percent, but a few specific users may see 100% errors.
Latency vs Throughput
Thinking about system latency vs throughput is something very similar to thinking about aggregate vs individual.
Our default behaviour when building anything is to think about the throughput first, but users care most about latency.
User perceived performance hinges on latency, and outliers in latency can lead to customer dissatisfaction which may not show up in your metrics.
Declarative vs Imperative
Do you define the solution in a step by step manner or describe the problem in a way which gives you the solution automatically?
The classic example here is of course SQL vs ad-hoc code.
Do you build DSLs or micro-DSLs that make it easier to solve the problem you're facing? Or is such an approach overkill for the current problem and you're better off avoiding unnecessary abstractions?
Top-down vs Bottom-Up
Top down: take a larger problem statement, break it down into modules, then modules into sub-modules, and repeat. Think big picture, think about boundaries and clean separation.
Bottom up: Find the small abstractions and vocabulary of the problem, define small parts that add up to a larger whole, 'discover' the larger solution by focusing on the axioms of the problem.
Bottom up may result in a more organic solution, or it may end up being a complete mess.
Can you seamlessly switch from one perspective to another? How does a change you apply bottom-up affect the top down vision, and vice-versa?
Summary
This list is probably incomplete. I may go back and keep adding to this list over time.
The question I keep asking myself is: what am I missing? What are some examples of perspectives that I'm not aware of?