Dependency management has not been discussed much on LAVA or in any of the NI material I've seen. Understanding its importance was one of those "Aha!" moments for me. Now creating a component dependency map is one of the very first architectural tasks I do, both on new projects and when taking over an existing code base. The VI Hierarchy window has the ability to collapse a library down to a single icon. That can be very useful for figuring out your dependencies in an existing project.
I don't have an easy "one size fits all" fix for breaking dependency cycles. The best solution depends on many project-specific considerations. However, here is an (incomplete) list of general guidelines...
1. Avoid dependency cycles. (I know I said it before, but IMO it ranks pretty high on the "rules not to break" list.)
2. Reuse components should *never* depend on application-specific components. Ideally reusable components have no other dependencies, though occasionally it may depend on another reusable component.
3. The dependency map doesn't need to be a tree. In other words, it's okay for 2 or more higher level components to depend on the same low level component.
4. Custom data types, such as classes and typedefs, tend to create lots of dependency links as the data is passed around the application. Off the top of my head here are three ways to work around that:
4a. Create a low-level, app-specific library for your custom data types and have all your non-reuse components depend on that.
4b. Use Labview's native data types to exchange information. A 2d string array makes a great lookup table for passing arbitrary information. (Note: Often using native types to exchange information increases the opportunities for runtime errors. It takes diligence to ensure you are adequately testing those possibilities.)
4c. Use "adapters" to convert from one data type to another. This can be especially useful when your reuse component communicates in generic or custom data types and you want to use a different, application specific data type.
[Note: In this thread, when I use the word "dependency," I am referring only to static, or compile-time, dependencies. Other types of dependencies include dynamic dependencies (depending on a dynamically loaded vi via path information) and definition dependencies (depending on a schema, protocol, or other definition not explicitly defined by code.) Managing those dependencies is important but beyond the scope of what I am discussing here.]
---------------------
[Edit - It will be well worth your time to learn about dependency injection. Don't know how I managed to forget mentioning that...]