"What real functional programmers do is 'multi-paradigm'– mostly functional, but with imperative techniques used when appropriate." Writing to a database or to the console or calling services is what makes an application useful. Instead of eschewing these, we try to make all dependencies and influence on the environment localized and explicit.
The difference between an imperative and functional thinking is "what should be the primary, default 'building block' of a program. To a functional programmer, it’s a referentially-transparent (i.e. returning the same output every time per input, like a mathematical function) function. In imperative programming, it’s a stateful action."
Imperative thinks of every line in the code as an action, as doing something. Functional thinks of every line as calculating something, and very specific lines as performing an action with external impact (database access, external API calls, etc). "Immutable data and referentially transparent functions should be the default, except in special cases where something else is clearly more appropriate."
The result of isolating those external effects is that more code is easily testable. More code can be properly unit-tested, while specific code that interacts with the outside world can only be integration tested: "One needs to be able to know (and usually, to control) the environment in which the action occurs in order to know if it’s being done right" in imperative code." Those are the failure points in our application. Don't bury them under mounds of indirection or scatter them throughout your code.
In sum, "we don’t always write stateless programs, but we aim for referential transparency or for obvious state effects."
Without the Ghetto-slang of referential transparency, partial application, and reasoning about code, functional thinking boils down to: don't change shit until you have to, and when you have to, call it out.