Practical takeaway: take any piece of your system and draw a call graph with each layer on its own horizontal line. Any arrow pointing upward (e.g. a controller calling something that calls back into the controller; a view iterating over models; a decorator depending on its view) is a red flag that the layering is wrong. Use the graph to distinguish real abstractions (a date→human-string helper) from fake splits (concerns that move code across files without changing runtime dependencies). Apply this at function, class, app, microservice and layer scale — microservices that 'split modules across web servers and pray' fail precisely because their call graph has the same bad shape.