Esistono best practice per l'organizzazione di pacchetti (Java)? [chiuso]


201

Qualche tempo fa, ho visto una risposta a questa domanda riguardante l'organizzazione a grana fine dei pacchetti java. Ad esempio, my.project.util, my.project.factory, my.project.service, etc.

Non riesco a trovarlo ora, quindi posso anche porre la domanda.

Esistono buone pratiche per quanto riguarda l'organizzazione dei pacchetti in Java e cosa ne deriva?

Come organizzi le tue lezioni nel tuo progetto Java?

Ad esempio, un progetto a cui sto lavorando con alcune persone ha un pacchetto chiamato bean. È iniziato con un progetto che conteneva fagioli semplici, ma è finito (attraverso una scarsa esperienza e mancanza di tempo) contenente tutto (quasi). Li ho ripuliti un po ', inserendo alcune classi factory in un pacchetto factory (classi con metodi statici che creano bean) ma abbiamo altre classi che eseguono la logica aziendale e altre che eseguono una semplice elaborazione (non con la logica aziendale) come il recupero un messaggio per un codice da un file delle proprietà.

I tuoi pensieri e commenti sono apprezzati.


74
Non sono d'accordo con la chiusura di questa domanda. Non sono d'accordo sul fatto che le domande sulle migliori pratiche siano quasi sempre basate sull'esperienza e sull'opinione, tuttavia, non sono d'accordo sul fatto che queste domande debbano essere chiuse su Stack Overflow. Questo è il punto cruciale della buona programmazione, usare le migliori pratiche e trovare la soluzione migliore utilizza queste opinioni ed esperienze. Riapri questa domanda.
Cyntech,

Ti suggerisco di leggere questo: satisfice.com/blog/archives/5164 . TL; DR ... l'intera idea di "buone pratiche" è rotta. Nella migliore delle ipotesi è un termine improprio, nel peggiore dei casi è decisamente dannoso.
Stephen C,

Risposte:


174

L'organizzazione del pacchetto o la strutturazione del pacchetto sono di solito una discussione accesa. Di seguito sono riportate alcune semplici linee guida per la denominazione e la strutturazione dei pacchetti:

  • Seguire le convenzioni di denominazione dei pacchetti java
  • Strutturare i pacchetti in base al ruolo funzionale e al ruolo aziendale
    • Suddividere i pacchetti in base alla loro funzionalità o moduli. per esempio com.company.product.modulea
    • Un'ulteriore suddivisione potrebbe essere basata su livelli nel software. Ma non esagerare se hai solo poche classi nel pacchetto, allora ha senso avere tutto nel pacchetto. es . com.company.product.module.webo com.company.product.module.utilecc.
    • Evitare di esagerare con la strutturazione, IMO evitare imballaggi separati per eccezioni, fabbriche, ecc. A meno che non vi sia una necessità urgente.
  • Se il tuo progetto è piccolo, mantienilo semplice con pochi pacchetti. es com.company.product.modele com.company.product.util, etc.
  • Dai un'occhiata ad alcuni dei popolari progetti open source disponibili sui progetti Apache . Guarda come usano la strutturazione, per progetti di varie dimensioni.
  • Considera anche la generazione e la distribuzione durante la denominazione (che ti consente di distribuire l'API o l'SDK in un pacchetto diverso, vedi l'APP servlet)

Dopo alcuni esperimenti e prove dovresti essere in grado di trovare una struttura con cui ti senti a tuo agio. Non essere fissato su una convenzione, sii aperto alle modifiche.


Grazie per la risposta. Questo è in gran parte ciò che abbiamo cercato di comprendere, ma un sacco di codice non correlato è entrato nel nostro pacchetto bean, da dove è nata la mia domanda.
Cyntech,

2
Sono d'accordo che il pacchetto per funzionalità ha più senso. Ho sentito una grande analogia una volta legata alla struttura di un ufficio aziendale. In un approccio a più livelli, ciascuno degli individui per livello in una società si sederebbe l'uno con l'altro, vale a dire Dirigenti, dirigenti, amministratori, impiegati / lavoratori seduti in sezioni separate in un edificio. Questa struttura probabilmente non è efficace come un approccio organizzato "caratteristica". Vale a dire se il direttore delle vendite si siede con il direttore delle vendite che si siede con i dipendenti delle vendite che siedono tutti con un amministratore delle vendite. Ciò fornisce una migliore coesione tra il dipartimento quando organizzato in questo modo.
alex,

Accetto i tuoi punti. Solo un punto per evidenziare il nome dell'azienda nel pacchetto alcune volte che l'azienda viene acquistata il prodotto viene venduto. La direzione desidera rimuovere il nome dell'azienda. Potrebbe essere un problema.
Tushar D

183

Organizzo i pacchetti per funzionalità , non per modelli o ruoli di implementazione. Penso che pacchetti come:

  • beans
  • factories
  • collections

sono sbagliati.

Preferisco, ad esempio:

  • orders
  • store
  • reports

così posso nascondere i dettagli dell'implementazione attraverso la visibilità del pacchetto . La fabbrica degli ordini dovrebbe essere nel orderspacchetto, quindi i dettagli su come creare un ordine sono nascosti.


10
Questo post sottolinea la visibilità del pacchetto. Non ho mai visto l'ambito del pacchetto Java in uso, ma la giusta struttura del pacchetto potrebbe consentire agli sviluppatori di trarne un vantaggio maggiore.
Jpnh,

23
Questo è esattamente giusto, ma pochi sviluppatori lo fanno. I pacchetti dovrebbero essere raccolte di classi coerenti, alcune delle quali sono visibili solo all'interno del pacchetto. Ciò minimizzerebbe l'accoppiamento tra classi che non dovrebbero essere accoppiate perché riguardano caratteristiche diverse. L'approccio pacchetto per strato, non sfrutta i modificatori della visibilità dei pacchetti e i pacchetti in un tale progetto hanno una bassa coesione e un elevato grado di accoppiamento tra i pacchetti.
Nate Reed,

Ne hai un esempio? Sto usando Spring-MVC trovo difficile organizzarlo per funzione / modulo perché spring usa config xml.
Eric Huang,

2
@onof Organizzo anche il mio codice per funzionalità, ma quali sono le migliori pratiche per le classi di base condivise da tutte le funzionalità?
Marc

Stavo seguendo il primo stile. ma ora devo passare da un pacchetto all'altro quando lavoro con le classi. è davvero una brutta esperienza. Passo ora al secondo stile perché penso che sarà più facile seguire le lezioni correlate insieme.
M.kazem Akhgary,

40

Risposta breve: un pacchetto per modulo / funzione, possibilmente con sotto-pacchetti. Metti insieme cose strettamente correlate nello stesso pacchetto. Evita dipendenze circolari tra i pacchetti.

Risposta lunga: sono d'accordo con la maggior parte di questo articolo


2
i pacchetti secondari rompono l'incapsulamento. Un "sotto-pacchetto" è in realtà un pacchetto completamente indipendente da solo
Ricardo Gamba,

21

Preferisco le funzionalità prima dei livelli, ma immagino che dipenda dal tuo progetto. Considera le tue forze:

  • dipendenze
    Prova a ridurre al minimo le dipendenze dei pacchetti, in particolare tra le funzionalità. Estrai le API se necessario.
  • Organizzazione del team
    In alcune organizzazioni i team lavorano sulle funzionalità e in altri sui livelli. Ciò influenza l'organizzazione del codice, lo usa per formalizzare le API o incoraggiare la cooperazione.
  • Distribuzione e controllo delle versioni
    Mettere tutto in un modulo semplifica la distribuzione e il controllo delle versioni, ma la correzione dei bug è più difficile. Dividere le cose consente un migliore controllo, scalabilità e disponibilità.
  • Rispondi al cambiamento Un
    codice ben organizzato è molto più semplice da modificare rispetto a una grande palla di fango.
  • Dimensioni (persone e righe di codice)
    Più è grande, più deve essere formalizzata / standardizzata.
  • Importanza / qualità
    Alcuni codici sono più importanti di altri. Le API dovrebbero essere più stabili dell'implementazione. Pertanto deve essere chiaramente separato.
  • Livello di astrazione e punto di ingresso
    Dovrebbe essere possibile per un estraneo sapere di cosa tratta il codice e dove iniziare a leggere guardando l'albero dei pacchetti.

Esempio:

com/company/module
  + feature1/
    - MainClass          // The entry point for exploring
    + api/               // Public interface, used by other features
    + domain/
      - AggregateRoot
      + api/             // Internal API, complements the public, used by web
      + impl/ 
    + persistence/       
    + web/               // presentation layer 
    + services/          // Rest or other remote API 
    + support/            
  + feature2/
  + support/             // Any support or utils used by more than on feature
    + io
    + config
    + persistence
    + web

Questo è solo un esempio. È abbastanza formale. Ad esempio, definisce 2 interfacce per feature1 . Normalmente ciò non è richiesto, ma potrebbe essere una buona idea se utilizzato in modo diverso da persone diverse. È possibile consentire all'API interna di estendere il pubblico.

Non mi piacciono i nomi 'impl' o 'support', ma aiutano a separare le cose meno importanti da quelle importanti (dominio e API). Quando si tratta di nominare, mi piace essere il più concreto possibile. Se hai un pacchetto chiamato "utils" con 20 classi, passa StringUtilsa support / string, HttpUtila support / http e così via.


13

Esistono buone pratiche per quanto riguarda l'organizzazione dei pacchetti in Java e cosa ne deriva?

Non proprio no. Ci sono molte idee e molte opinioni, ma la vera "migliore pratica" è usare il buon senso!

(Leggi No Best Practices per una prospettiva sulle "best practice" e le persone che le promuovono.)

Tuttavia, esiste un principio che ha probabilmente un'ampia accettazione. La struttura del pacchetto deve riflettere la struttura del modulo (informale) dell'applicazione e si dovrebbe mirare a minimizzare (o idealmente evitare del tutto) qualsiasi dipendenza ciclica tra i moduli.

(Le dipendenze cicliche tra le classi in un pacchetto / modulo vanno bene, ma i cicli tra pacchetti tendono a rendere difficile comprendere l'architettura dell'applicazione e possono essere un ostacolo al riutilizzo del codice. In particolare, se usi Maven scoprirai che ciclica le dipendenze tra pacchetti / tra moduli significano che l'intero casino interconnesso deve essere un artefatto di Maven.)

Vorrei anche aggiungere che non v'è una migliore prassi ampiamente accettato per i nomi dei pacchetti. Ciò significa che i nomi dei pacchetti devono iniziare con il nome di dominio dell'organizzazione in ordine inverso. Se segui questa regola, riduci la probabilità di problemi causati dallo scontro tra i tuoi nomi di classe (completi) con quelli di altre persone.


9

Ho visto alcune persone promuovere 'pacchetto per funzione' piuttosto che 'pacchetto per strato' ma ho usato parecchi approcci per molti anni e ho trovato 'pacchetto per strato' molto meglio di 'pacchetto per funzione'.

Inoltre ho scoperto che un ibrido: la strategia "pacchetto per modulo, strato quindi funzione" funziona molto bene nella pratica in quanto presenta molti vantaggi di "pacchetto per funzione":

  • Promuove la creazione di framework riutilizzabili (librerie con aspetti sia del modello che dell'interfaccia utente)
  • Consente implementazioni di layer plug-and-play - praticamente impossibili con 'package by feature' perché colloca le implementazioni di layer nello stesso pacchetto / directory del codice modello.
  • Molti altri...

Spiego in dettaglio qui: struttura e organizzazione del nome del pacchetto Java ma la mia struttura di pacchetti standard è:

revdomain.moduleType.moduleName.layer. [layerImpl] .feature.subfeatureN.subfeatureN + 1 ...

Dove:

revdomain Dominio inverso, ad es. com.mycompany

moduleType [app * | framework | util]

moduleName, ad esempio myAppName se il tipo di modulo è un'app o "finanza" se è un framework contabile

layer [modello | ui | persistenza | sicurezza ecc.]

layerImpl es., wicket, jsp, jpa, jdo, hibernate (Nota: non utilizzato se layer è modello)

caratteristica ad es., finanza

caratteristica secondaria N ad es. contabilità

caratteristica secondaria N + 1 ad es. ammortamento

* A volte 'app' viene esclusa se moduleType è un'applicazione ma inserirla rende la struttura del pacchetto coerente per tutti i tipi di modulo.


5

Non sono a conoscenza delle pratiche standard per l'organizzazione del pacchetto. Generalmente creo pacchetti che coprono uno spettro abbastanza ampio, ma posso differenziare all'interno di un progetto. Ad esempio, un progetto personale a cui sto attualmente lavorando ha un pacchetto dedicato ai miei controlli dell'interfaccia utente personalizzati (pieno di classi che classificano le classi swing). Ho un pacchetto dedicato alle mie cose di gestione del database, ho un pacchetto per una serie di listener / eventi che ho creato e così via.

D'altra parte ho avuto un collega creare un nuovo pacchetto per quasi tutto ciò che ha fatto. Ogni diverso MVC che voleva aveva il suo pacchetto, e sembrava che un set MVC fosse l'unico raggruppamento di classi a cui era permesso essere nello stesso pacchetto. Ricordo che a un certo punto aveva 5 pacchetti diversi, ciascuno con una sola classe. Penso che il suo metodo sia un po 'estremo (e il team lo ha costretto a ridurre il conteggio dei pacchetti quando semplicemente non potevamo gestirlo), ma per un'applicazione non banale, quindi metterebbe tutto nello stesso pacchetto. È un punto di equilibrio che tu e i tuoi compagni di squadra dovete trovare da soli.

Una cosa che puoi fare è provare a fare un passo indietro e pensare: se tu fossi un nuovo membro presentato al progetto, o il tuo progetto fosse rilasciato come open source o API, quanto sarebbe facile / difficile trovare quello che vuoi? Perché per me, questo è quello che voglio davvero dai pacchetti: organizzazione. Simile al modo in cui memorizzo i file nella cartella sul mio computer, mi aspetto di poterli ritrovare senza dover cercare in tutto il mio disco. Mi aspetto di riuscire a trovare la classe desiderata senza dover cercare nell'elenco di tutte le classi nel pacchetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.