Come devo organizzare il mio albero dei sorgenti?


89

Sono un singolo sviluppatore che lavora, in gran parte, su progetti web (W / LAMP) e, a volte, su progetti C / C ++ (non-GUI) su scala media.

Spesso faccio fatica a strutturare il mio albero di codice sorgente. In effetti, di solito, non completo un progetto senza scaricare l'intero albero e riordinare i pezzi tre o quattro volte, il che richiede molto sforzo e inoltre il risultato finale sembra un compromesso.

A volte, finisco con un'eccessiva classificazione dei sorgenti - albero molto lungo di cartelle e sottocartelle. Altre volte, finisco semplicemente per concentrare tutti i file in una determinata cartella in base allo scopo più ampio che servono e portando così a cartelle "caotiche" nell'origine.

Vorrei chiedere:

  • Esistono principi / logiche / buone pratiche che possono aiutarmi a strutturare meglio il mio albero dei sorgenti?
  • Esistono tecniche grafiche / diagrammatiche (ad es. DFD in caso di flusso di dati) che possono aiutarmi a visualizzare in anticipo il mio albero dei sorgenti in base all'analisi del progetto?
  • Quale strategia adottare per strutturare l'albero dei file multimediali associato al progetto?

Informazioni sulla generosità : apprezzo le risposte esistenti con i membri che condividono le proprie pratiche, tuttavia, vorrei incoraggiare risposte (o risorse) più generali e istruttive e più risposte da parte dei membri.


8
Non ho tempo per un saggio in questo momento, ma "nomina le cose per quello che sono", "metti le cose a cui appartengono", "tieni le cose simili vicine tra loro" e, infine, "non ti preoccupare , spero che tu abbia un IDE che ti aiuti a navigare rapidamente tra le parti di codice ".
John Saunders,

@Giovanni, non sono così bravo con gli IDE, in genere estraggo un Blocco note ++ o vi a seconda del sistema operativo. Questo rende le cose un po 'più difficili. Il resto dei punti sono utili, ma di nuovo si riduce a prendere decisioni difficili come le funzioni di registro (log degli errori, ecc.) Più vicine alla logica dell'applicazione o alla gestione DAL o cache o ai gestori delle viste. Gli errori hanno quasi la stessa probabilità di verificarsi in ognuno di essi.
check123

3
Forse una volta arrivato al punto di avere questo tipo di domanda, è tempo di lasciare che alcuni strumenti facciano del lavoro per te. E la registrazione è chiaramente una preoccupazione interfunzionale, utilizzata da tutte le parti dell'applicazione (se si utilizza il tipo di codice che richiede la registrazione). Un altro piccolo detto è "metti il ​​codice sopra il codice che lo usa", quindi la registrazione dovrebbe essere vicino all'inizio, forse in \ utilities.
John Saunders,

@Giovanni: molto apprezzato. Forse dovrei iniziare a cercare un IDE. Eclipse sembra promettente.
check123

1
@ check123 "... riordinando i pezzi tre o quattro volte ..." Pratica comune: "La domanda di gestione, quindi, non è se costruire un sistema pilota e buttarlo via. Lo farai. L'unica domanda è se pianificare in anticipo per costruire un lancio o promettere di consegnare il lancio ai clienti. "- Frederick P. Brooks Jr., The Mythical Man-Month: Essays on Ingegneria del software
shawnhcorey

Risposte:


25

Il layout dell'albero di origine dovrebbe riflettere l'architettura; come corollario, un'architettura ben strutturata può portare a una struttura ad albero della sorgente ben strutturata. Suggerisco di leggere sul modello dei livelli POSA1 , tentare di adattare la propria architettura a una struttura a più livelli, quindi nominare ciascuno dei livelli risultanti e utilizzarlo come base per la gerarchia di origine. Prendendo come base una comune architettura a tre livelli :

  • presentazione / webService (presentare un'interfaccia di servizio web alla nostra logica aziendale)
  • logic / * (i moduli di business logic vanno qui)
  • storage / sql (API di archiviazione back-end qui: utilizza un'interfaccia SQL per archiviare in un database)
  • util / * (codice utility - utilizzabile da tutti gli altri layer, ma che non fa riferimento a util esterno, va qui)

Si noti che i livelli non contengono direttamente il codice, ma piuttosto sono strettamente utilizzati per organizzare i moduli.

All'interno di un modulo, utilizzo il seguente tipo di layout:

  • <module> (percorso al modulo direttamente; definisce l'interfaccia modulare)
  • <module>/impl/<implName> (un'implementazione specifica dell'interfaccia modulare)
  • <module>/doc (Documentazione per l'utilizzo del modulo)
  • <module>/tb (codice unit-test per il modulo)

dove <module>si trova nel repository in base al layer a cui appartiene.


5
+1: il layout dell'albero di origine dovrebbe riflettere l'architettura - una cosa ovvia che stavo trascurando.
Check123

Come gestite i file protetti - file a cui solo gli utenti autorizzati possono accedere dopo l'accesso?
check123

@ check123 Non sono sicuro di aver capito la domanda. Mi sono concentrato sull'organizzazione dei moduli sorgente, piuttosto che sul supporto dei file per il progetto, e il codice sorgente è generalmente destinato a essere accessibile a tutti. (Ci sono eccezioni, e io uso una directory dist / soprattutto codice con restrizioni di uso / modifica non standard.)
Aidan Cully

48

Non posso davvero darti molti consigli relativi ai progetti web, ma ecco come strutturo il mio albero in un progetto di programmazione (principalmente dal punto di vista C / C ++):

  • /
    • src - File di origine scritti da me stesso
    • ext - Contiene librerie di terze parti
      • libname-1.2.8
        • include : intestazioni
        • lib - File lib compilati
        • Donwload.txt: contiene il collegamento per scaricare la versione utilizzata
    • ide - I file di progetto vengono archiviati qui
      • vc10 - Organizzo i file di progetto in base all'IDE
    • bin - Exe compilato va qui
    • build - I file di compilazione del compilatore
    • doc - Documentazione di qualsiasi tipo
    • LEGGIMI
    • INSTALLARE
    • COPIA

Alcune note:

  1. Se sto scrivendo una libreria (e sto usando C / C ++) organizzerò prima i miei file sorgente in due cartelle chiamate "include" e "src" e poi per modulo. Se si tratta di un'applicazione, li organizzerò solo per modulo (le intestazioni e le fonti andranno nella stessa cartella).

  2. I file e le directory che ho elencato sopra in corsivo non aggiungerò al repository di codice.


Qual è la differenza tra ide e build ?
M. Dudley,

3
ideè proprio dove memorizzo i file di progetto stessi. buildcontiene i file oggetto generati dal compilatore. IDE diversi possono utilizzare lo stesso compilatore, quindi è per questo che mantengo i file di progetto IDE separati dai file oggetto creati dal compilatore.
Paul,

quindi build == obj (il termine usato da molti altri sistemi)
gbjbaanb

@gbjbaanb Sì, immagino. Non importa davvero perché quella directory non viene trasferita nel repository. :) L'ho chiamato 'build' perché è così che l'IDE che stavo usando att lo chiamava (Visual Studio).
Paul,

E se il tuo exe avesse bisogno di qualche dll per funzionare? Copi tutti i file dll nella stessa directory di exe? Usi alcuni eventi post-build?
Wakan Tanka,

14

Mentre il layout di directory standard di Maven è specifico per Java, ma può essere una buona base anche per altri tipi di progetti.

Ecco la struttura di base (è possibile sostituire le directory 'java' con 'php', 'cpp', ecc.):

src/main/java       Application/Library sources 
src/main/resources  Application/Library resources  
src/main/filters    Resource filter files 
src/main/assembly   Assembly descriptors 
src/main/config     Configuration files 
src/main/webapp     Web application sources 
src/test/java       Test sources 
src/test/resources  Test resources 
src/test/filters    Test resource filter files 
src/site            Site 
LICENSE.txt         Project's license 
NOTICE.txt          Notices and attributions required by libraries
README.txt          Project's readme

La struttura si suddivide sostanzialmente in "src / main" e "src / test", quindi raggruppati per tipo.


5

Non conosco davvero le convenzioni, ma tutti i miei progetti principali sono realizzati con Symfony Framework e mi sono abituato a una struttura ad albero come segue:

radice/

  • applicazioni
  • nome dell'applicazione
    • config (file di configurazione specifici dell'app)
    • lib (file php specifici dell'app)
    • moduli (distribuzione modulare della funzionalità)
      • nome_modulo
        • modelli (html)
        • azioni (codice php)
  • confing (file di configurazione del progetto)
  • lib (codice php che potrebbe essere usato nel progetto hole)
  • modello (classi che rappresentano le informazioni sul progetto)
    • base
  • form (file php che gestiscono i form, questo potrebbe essere abbastanza difficile da ottenere senza symfony)
    • base (classi del modulo di base)
  • rete
  • css
    • immagini
    • file.css
  • js
  • log (file di log che potrebbero essere generati)
  • dati (informazioni specifiche sui dati, come patch sql o altro)
  • sql
  • plug-in (librerie utilizzate che potrebbero essere unite a qualsiasi app del progetto)

Se sei interessato, leggi la documentazione di symfony sull'argomento per ulteriori informazioni ( MVC e Code Organization su Symfony ).


La tua cartella CSS è centralizzata? Voglio dire, tutti i tuoi CSS (attraverso il progetto) si trovano nella stessa directory?
check123

Non necessariamente, potresti dividerlo, ma poiché la maggior parte dei miei progetti tende ad avere solo 2 app (frontend e backend), non ci sono molti file CSS (i plug-in hanno sempre la propria cartella web per l'astrazione)
guiman

5

Idealmente, l'organizzazione ha un unico repository, la cui struttura è destinata ad aumentare il coinvolgimento tra ingegneria e business e promuovere il riutilizzo.

...\products\
...\products\productName\
...\products\productName\doc\

...\systems\
...\systems\systemName\
...\systems\systemName\doc\
...\systems\systemName\res\
...\systems\systemName\build\
...\systems\systemName\test\

...\library\
...\library\libraryName\
...\library\libraryName\doc\
...\library\libraryName\build\
...\library\libraryName\test\

...\devops\

prodotti

Una cartella per prodotto; aiuta a comunicare come il software supporta l'azienda.

Idealmente, ogni "prodotto" è poco più di un file di configurazione che indica quali sistemi richiamare e come devono essere configurati. La sottocartella del documento potrebbe contenere il brief \ spec di livello superiore e qualsiasi materiale promozionale ecc ...

Separando prodotti e sistemi, comunichiamo il potenziale di riutilizzo al lato dell'azienda rivolto ai clienti e suddividiamo i silos per prodotto. (Ciò contrasta con l'approccio della "linea di prodotti" allo stesso problema)

sistemi

Una cartella per sistema; aiuta a comunicare le principali capacità e opportunità / valore dei contenuti del repository.

  1. File "Gestione della configurazione" che specificano gli ambienti di compilazione e distribuzione.
  2. Configurazione di test a livello di sistema (potrebbe essere una quantità significativa).
  3. Logica e funzionalità ai massimi livelli; il sollevamento più pesante viene eseguito dalle funzioni di libreria.

biblioteca

Componenti riutilizzabili invocati da vari sistemi. La maggior parte delle attività di sviluppo sono organizzate attorno alla produzione di librerie, piuttosto che ai sistemi, quindi il riutilizzo è "integrato" nel processo di sviluppo.

DevOps

Creazione, integrazione continua e altre funzionalità di automazione dello sviluppo.

Conclusione

L'albero dei sorgenti è un elemento chiave della documentazione e modella l'approccio, la struttura e la psicologia del rapporto tra l'azienda e la sua tecnologia proprietaria.

I driver per questo approccio sono spiegati un po 'più in profondità nella mia risposta a questa domanda: https://softwareengineering.stackexchange.com/questions/43733/who-organizes-your-matlab-code/59637#59637


Nota: può essere utile assegnare un nome alle cartelle in modo compatibile con il tipo di gerarchie di prodotti discusse nel manuale di ingegneria dei sistemi INCOSE.
William Payne,

3

Quello che sto cercando di fare per ogni progetto è simile al seguente:

  • src - file di origine, una cartella per ogni spazio dei nomi / pacchetto per recuperare facilmente i file (anche i file di intestazione per C / C ++)
  • ext - per le librerie esterne / di terze parti, è semplice aggiungere esterne (come i repository SVN). All'interno, una cartella per ciascuna libreria (file binari e include)
  • bin : per i file binari incorporati, potrebbe essere rapidamente esportato per il rilascio
    • inc - per file di intestazioni C / C ++ (copiato da IDE / makefile / etc ...)
  • out - per tutti i file generati temporaneamente (.class, .obj ecc ...) e potrebbe essere ignorato (ad esempio da SVN)
  • doc - per qualsiasi documentazione, generalmente generata con Doxygen
  • res - inserendo le risorse qui, è possibile separare i file di origine del testo e le risorse binarie utilizzate dal programma. Non ho davvero una gerarchia specifica dentro.
    • config - per alcuni file di configurazione
    • disegnabile - per alcune immagini o icone

Tutti i file o makefile di IDE vengono salvati direttamente nella radice se ne usi solo uno.


2

Faccio qualcosa del genere. Funziona bene per un gioco multipiattaforma che sto facendo nel mio tempo libero. Purtroppo nel lavoro, le cose sono molto meno organizzate ...

Output                      <-- Build outputs
Docs
External
   <libname>
      Include
      Lib
Data
<ProjectName>.xcodeproj
<ProjectName>VS2010
Source
Temp                        <-- Intermediate stuff from builds and other tools
Tools

2

Per i miei team, cerchiamo di imporre una struttura standard in tutti i progetti per rendere facile trovare le cose mentre il team cambia contesto ed evitare di dover imparare di nuovo ogni volta. Non tutti i progetti richiedono tutti i sistemi, quindi iniziamo con il set minimo.

/ Fonte / Component / Lingua

/ Sorgente / Componente / Terze parti /

/ Documentazione / Requisiti

/ Documentazione / Design

/ Test / Automated / Unità

/ Test / Automated / ToolName

/ Test / manuale

Ciò si traduce in una duplicazione, in particolare sotto il codice e le librerie di terze parti, ma almeno non dimentichiamo mai la risposta a qualcosa come "Che cosa utilizza l'editor RogueWave?"


1
I componenti del percorso in maiuscolo mi sembrano davvero sciocchi e inutili. Perché molto tutto in minuscolo? È molto più facile da digitare per gli umani (mentre agli strumenti non interessa, inclusi i file manager WIMP ), e legge ugualmente bene grazie ai separatori di percorso. Una vittoria definitiva per me.
Ulidtko,

2

Mi piacciono le idee presentate in questa pagina www.javapractices.com/topic/TopicAction.do?Id=205 . Fondamentalmente, la raccomandazione è di organizzare il progetto in caratteristiche (o moduli, componenti). Oltre ai motivi qui presentati:

  1. Meno carico cognitivo quando si pensa all'ambito del codice su cui si sta lavorando poiché si ha la garanzia che qualsiasi codice nella funzione su cui si sta lavorando sia "feature-private".
  2. Vi è un ulteriore senso di sicurezza quando si garantisce che si sta modificando il codice solo per una determinata funzionalità. Ad esempio, non romperai altro che la funzione su cui stai lavorando. Ancora una volta questo è dovuto alla "funzione privata".
  3. Meno carico cognitivo semplice perché ci sono meno file che puoi vedere per un determinato pacchetto. Sono sicuro che tutti hanno visto un pacchetto che contiene più di 15 file.

Nota che questo è focalizzato sui pacchetti Java (aka namespace). Per i grandi progetti, consiglio, per le stesse ragioni, di dividere il progetto in più progetti (come in più progetti maven) che rappresentano una caratteristica aziendale. Per i progetti maven, consiglio questa lettura .

Finora, i progetti in cui ero / sono coinvolto non seguono questi. Ci sono molte ragioni, ma eccone alcune:

  1. Il fraintendimento del modificatore di accesso predefinito Java (modificatore di accesso più frainteso secondo questo libro )
  2. "Argumentum ad populum": cultura prevalente del pacchetto per strato (probabilmente causata dal motivo n. 1)

Penso che ci sia un'occasione mancata per prevenire la complessità se l'organizzazione della fonte del progetto non è presa sul serio all'inizio del progetto, come ha detto l'architetto Alexander:

"Come ogni designer ti dirà, sono i primi passi in un processo di progettazione che contano di più. I primi tratti, che creano la forma, portano in sé il destino del resto." - Christopher Alexander

A seconda delle dimensioni e della complessità di un progetto, la mancata opportunità di ridurre i costi o il ROI può essere davvero grande. (Sono interessato a vedere uno studio per vedere i numeri esatti per questo)


2

La mia raccomandazione è di scaricare una varietà di framework o motori e vedere come enormi team di sviluppo hanno gestito il layout delle loro cartelle.

Ci sono così tanti modi per organizzare i file che è meglio sceglierne uno e provare a rispettarlo in qualsiasi progetto. Attenersi a una particolare convenzione fino al completamento o al rinnovo per evitare bug e perdere tempo inutile.

È possibile scaricare i framework Laravel, Symphony o Codeigniter per progetti Web per avere un layout di cartella istantaneo che funzioni.

Quindi proverò a trasmettere un layout di cartelle comune a qualsiasi sviluppo:

MVC (Model View Controller) offre un buon paradigma di organizzazione.

Il codice sorgente radice potrebbe essere src (C ++) o app (sviluppo web)

Una struttura di file che non ha un obiettivo chiaro per le classi che raggruppa sicuramente causerà confusione. Non è solo per organizzare il codice, ma può supportare caricatori automatici, factory di classe, wrapping di archiviazione locale, archiviazione remota e spazio dei nomi.

Questa struttura di cartelle è derivata e semplificata da Laravel Framework . La mia preferenza su questo post è la denominazione plurale, ma uso parole singolari nei miei progetti.


src / storage (modelli / file-storage / api / mysql / sql-lite / memcached / implementazioni redis)

src / repository (un wrapper di "implementazioni di archiviazione" con una certa logica di archiviazione, un'interfaccia comune e una convenzione sui risultati di ritorno.)

src / services | logica | entità (logica di bussiness app)

src / controller (utilizzato nello sviluppo web per instradare le richieste del server ai tuoi servizi)

src / modules | sistemi ( sistemi modulari che estendono la funzionalità generale del framework. I servizi possono utilizzare i moduli ma non viceversa)

src / helpers (classi di helper o wrapper come ad es. manipolazione di stringhe. Molte volte questo potrebbe essere su libs | vendor quando di terze parti)

src / types (enum con nome)

pubblico | costruire | output (web o c ++)

config (file di installazione. YAML sta diventando popolare per i file di configurazione multipiattaforma)

nascondiglio

logs

lang (en / es / ru / ...)

bootstrap (avvia il framework e l'app)

docs (Documentazione scritta in formato markdown .md)

test (unit test)

database / migrations (Crea struttura del database da zero)

database / seed (riempie il database con dati fittizi da testare)

libs | fornitore (tutto il software di terze parti. 'libs' su C ++ e 'vendor' di solito su php)

attività | risorse (immagini / suoni / script / json / qualsiasi media)


1

Con linguaggi orientati agli oggetti, hai la possibilità di creare spazi dei nomi. Tale suddivisione logica utilizzata per separare parti dell'applicazione per evitare l'accoppiamento è la fonte principale di suddivisione della posizione dei file logici. L'uso dell'accoppiamento come motivo per spezzare gli spazi dei nomi è un buon punto di partenza http://en.wikipedia.org/wiki/Software_package_metrics .

Altri hanno parlato dell'installazione del progetto in relazione alla compilazione, ma una volta entrati nella fonte stessa, si tratta di ciò che ha senso - basta usare il modo in cui logicamente si divide il codice comunque.

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.