The principle of “Separation of Concerns” ought to be balanced with the principle of “Locality of Behavior”. This principle is derived from a Richard Gabriel’s paper, “Patterns of Software” (emphases mine):

Compression is the characteristic of a piece of text that the meaning of any part of it is “larger” than that piece has by itself. This is accomplished by the context being rich and each part of the text drawing on that context—each word draws part of its meaning from its surroundings.

Compression is a little dangerous because it requires the programmer to understand a fair amount about the context from which compressed code will take its meaning. Not only does this require available source code or excellent documentation, but the nature of inherited language also forces the programmer to understand the source or documentation. If a programmer needs a lot of context to understand a program he needs to extend, he may make mistake because of misunderstandings.

Furthermore, even if the new code—the compressed code—is compact, it will take at least as much time and effort to write as it would to write the uncompressed code, unless the overall complexity and size of the total code is small or unless the person writing the code has the existing code firmly in mind.

Maintaining compressed code requires understanding its context, which can be difficult. The primary feature for easy maintenance is locality: Locality is that characteristic of source code that enables a programmer to understand that source by looking at only a small portion of it.Richard Gabriel

As an example in front-end web dev, we could leverage something like HTMX to inline behavior (though not the implementation details of said behavior):

<button hx-get="/logs"
    hx-target="#output"
    hx-swap="innerHTML">Get Logs</button>

<output id="output"></output>

In plain English: “When the button is clicked, issue a GET request to the /logs endpoint and place its response content (presumed to be HTML and not a JSON response) in the element with the ID of “output”, swapping everything within the element.”

It’s a small example, but it hopefully communicates the general idea of “localizing” the behavior (especially useful if you have partial views you’d like to reuse), though not the implementation of said behavior. We don’t have to add in an extra JS file outside of the HTMX library itself. There is no imperative code in a separate file that we need to look back and forth in our editor to grok the full picture of what’s happening (this isn’t to say that imperative code is bad in itself). A mix of HTMX attributes on the appropriate elements makes it fairly easy to have dynamic behavior on a page without necessarily having to write imperative JS code that triggers “actions at a distance”.

HTMX is a recent example of applying this principle correctly and the ROI is pretty high, but it isn’t the only one, and it’s something you or your team to can leverage and implement in your own codebase.

And by way of reminder, any principle, pattern, or advice ought to be part of your toolkit and used when its need arises in your project, but not used as the metric or end in itself.