In my day job at Cantina, we just completed work on an event-driven, browser-based application. This was a fairly large application consisting of 8 pages with a total of over 50 page elements, each with a varying degree of interactivity. We leveraged Backbone to bind it all together.
For all the complexity, I'd say the one pattern that contributed most to this being a managable project was workflows. The word sounds a bit stuffy, but you don't need a certification or even a software library to make use of this idea.
I define a workflow as an a sequence of states which a module passes through in the course of an application's execution. It's a natural idea that comes out of the prerequisites of modules, such as needing data before you can render a template. In this case, the workflow could be as simple as:
instantiate -> fetch -> render
This idea can work on many scales, but if you have the luxury of stepping your entire application through the workflow step by step, much clarity results. In the above example, this would mean that no object will begin their fetch phase until all objects are instantiated, and so on.
Thinking in terms of workflows can make race conditions and data dependencies much simpler to reason about. Workflows introduce an abstraction of changes occurring over time. It helped us as we built our client-side web application. You can't bind events to a DOM element that isn't attached to the document root. This naturally leads to two discrete steps: render and bind.
It's also an opportunity to keep concerns separated. Doing all data retrieval within the 'fetch' stage will naturally keep the 'render' stage free of database calls.
The line in the sand
In some cases, we found that it was beneficial to formalize the workflow with code. In our Backbone application, we introduced the concept of pages, driven by routes, each with data services backing their contents. Rather than have our router control the retrieval of data and creation of views, we created a PageManager class to represent the page display workflow concern.
This resulted in a Page superclass, with methods named according to their workflow phase. This means that other developers can jump in and create pages after a quick walkthrough of the workflow. The workflow becomes a lightweight framework tailored to our application.
One of my favorite aspects of frameworks is to use them is to draw a line in the sand. It allows us to put aside large swaths of implementation details and stay focused on the problems we are solving. Introducing a workflow also establishes that separation. As an added benefit, both sides of the equation are still in your control since you introduced it!
Not a straight jacket
Lastly, I consider this to be a very lightweight concept. At a minimum it is a convention among developers. At its maximum, it is a separated concern which you manage in your repo. Adding phases to a workflow is a straightforward, unit-testable affair. Removing phases (which I've never needed to do) could be done by merging existing phases.
So that's my intro to workflows. I hope you find it to be a useful concept to keep in your toolbelt.