El indicador número uno de módulos mal acoplados en mi opinión son las dependencias bilaterales. Por ejemplo, el Módulo 1 llama a alguna función en el Módulo 2 y el Módulo 2 llama a alguna función en el Módulo 1.
La mayoría de las interfaces deben ser unidireccionales. Si el módulo al que se llamó necesita pasar alguna información al módulo de llamada que no se devuelve como parte de la llamada, entonces debería usar algún tipo de mecanismo de activación de eventos o paso de mensajes, como una cola de mensajes. Idealmente, el identificador para pasar la interfaz del mensaje debe pasarse durante algún proceso de inicialización o registro. Esto abstrae completamente la interfaz de tal manera que al módulo no le importa para quién es el evento ... por lo tanto, está desacoplado.
Otra indicación es cuando un módulo llama constantemente a otro módulo para un conjunto de datos específico. Esto debería hacerle preguntar quién debería ser el propietario del conjunto de datos. ¿Por qué este módulo en cuestión siempre necesita ver datos que pertenecen a otro módulo?
Una tercera herramienta, por así decirlo, es preguntarse: "¿Puedo extraer este módulo y reemplazarlo sin requerir cambios en otros módulos?
De ninguna manera es una lista exhaustiva, pero son las tres cosas principales que me pregunto cuando diseño un software.