In my experience, one of the best ways to fight complexity is by reducing the amount of things you have to keep in your head. In practical terms this translates into being able to do local reasoning about your code.
I find that imperative OO style naturally leads to complexity. Passing references to mutable data all over the place creates tight coupling across your entire application. This makes it impossible to guarantee that any change you make is local without considering every other place that references the data. Meanwhile, objects are opaque state machines and programs are structured by creating many interdependent objects.
These aspects make it pretty much impossible to tell what any particular piece of code is doing just by reading it in large applications. The only option is to fire up the debugger, get the app in a particular state and look at the data. However, there are typically many ways to get into any particular state, and it's really hard to know that you've accounted for them all. So, a debugger is a heuristic at best.
FP and immutability tackle both of these problems head on. Immutable data directly leads to the ability to do local reasoning about your code, and allows you to write pure functions that can be reasoned about independently. Meanwhile, data is not being abstracted inside opaque state machines that provide ad hoc DSLs as their API. Instead, it's explicitly passed through function pipelines to transform it.
Much of the time the "big picture" isn't local. That's just the nature of the big picture by definition. I find it better to put "big picture" stuff in the RDBMS, including UI issues (see "Table-Oriented" nearby), and keep only local details in code.
For example, the menus and navigation can almost all be tracked and managed in the RDBMS. It's easier to query and study the structure that way because I can sort, search, group, and filter it by any way --I-- please for any given need; I don't want to be stuck with YOUR single grouping; I want to be the Grouping God when studying the app. File-centric code can't do that (at least not without an IDE that reinvents a database). Therefore, don't do it. Use code where code is best, and RDBMS where RDBMS is best.
Code sucks at the big-picture and FP won't change that.
My team regularly hires co-op students who have no trouble solving all kinds of problems, as well as implementing features. I'm not sure where you get the notion that it's not a common thing?
I find that imperative OO style naturally leads to complexity. Passing references to mutable data all over the place creates tight coupling across your entire application. This makes it impossible to guarantee that any change you make is local without considering every other place that references the data. Meanwhile, objects are opaque state machines and programs are structured by creating many interdependent objects.
These aspects make it pretty much impossible to tell what any particular piece of code is doing just by reading it in large applications. The only option is to fire up the debugger, get the app in a particular state and look at the data. However, there are typically many ways to get into any particular state, and it's really hard to know that you've accounted for them all. So, a debugger is a heuristic at best.
FP and immutability tackle both of these problems head on. Immutable data directly leads to the ability to do local reasoning about your code, and allows you to write pure functions that can be reasoned about independently. Meanwhile, data is not being abstracted inside opaque state machines that provide ad hoc DSLs as their API. Instead, it's explicitly passed through function pipelines to transform it.