E’, in effetti, un problema che è sempre stato una croce. Tempo fa ho provato ad adottare questo pattern:
tabella_a, tabella_b, join_a_b
Nel tuo caso abbiamo contatti, gruppi di contatti, ed abbiamo bisogno del join:
contact, group_contact, join_contact_group
Come soluzione non è troppo verbosa, di facile lettura. In oltre percepisci da subito che "join_" è una tabella creata per uno scopo ben preciso. Non conosco Best Practice in questo campo, ma questa mi sembra una buona soluzione. In alternativa, per essere ancora più sintetico potresti fare questo:
contact, group_contact, _contact_group
oppure:
contact, group_contact, _contact__group_contact
Anche in quest’ultimo caso sei sintetico, riesci a leggere immediatamente il nome delle due tabelle. Io, personalmente, non sono per la sintesi. Mi focalizzo sul codice PHP piuttosto che sul nome della tabella. Questo perché cerco di avere un approccio completamente staccato dal database: le modifiche tendo a farle con le migrations. Quindi, secondo questa logica avremmo le classi:
Contact
ContactGroup
Il resto, per me, è poco importante: io ho gli occhi sempre puntati sul codice, e non sul database. Gestire il database con le migrations ed usare le fixtures ti può aiutare a rimodellare il database ogni volta che vuoi. A condizione che tu stia testando il tuo codice perché in caso contrario questa operazione diventa più complessa.