Domanda

Il mio collega afferma che dovremmo sezionare la nostra applicazione C ++ (C ++, Linux) in librerie condivise per migliorare la modularità del codice, la testabilità e il riutilizzo.

Dal mio punto di vista è un onere poiché il codice che scriviamo non ha bisogno di essere condiviso tra le applicazioni sulla stessa macchina né di essere caricato o scaricato dinamicamente e possiamo semplicemente collegare un'applicazione eseguibile monolitica.

Inoltre, il wrapping delle classi C ++ con le interfacce della funzione C IMHO lo rende più brutto.

Penso anche che l'applicazione a file singolo sarà molto più semplice per l'aggiornamento remoto sul sito di un cliente.

È necessario utilizzare le librerie dinamiche quando non è necessario condividere il codice binario tra le applicazioni e non è necessario caricare il codice dinamico?

È stato utile?

Soluzione

Direi che suddividere il codice in librerie condivise per migliorare senza avere alcun obiettivo immediato in mente è un segno di un ambiente di sviluppo infestato da parole d'ordine. È meglio scrivere codice che può essere facilmente diviso ad un certo punto.

Ma perché dovresti avvolgere le classi C ++ nelle interfacce della funzione C, tranne, forse, per la creazione di oggetti?

Inoltre, suddividere in librerie condivise qui sembra una mentalità linguistica interpretata. Nei linguaggi compilati si tenta di non rimandare al runtime ciò che è possibile fare in fase di compilazione. Il collegamento dinamico non necessario è esattamente il caso.

Altri suggerimenti

L'applicazione delle librerie condivise garantisce che le librerie non abbiano dipendenze circolari. L'uso delle librerie condivise spesso porta a un collegamento più rapido e gli errori di collegamento vengono rilevati in una fase precedente rispetto a quando non esiste alcun collegamento prima che l'applicazione finale venga collegata. Se vuoi evitare di spedire più file ai clienti, puoi considerare di collegare l'applicazione in modo dinamico nel tuo ambiente di sviluppo e staticamente durante la creazione di build di rilascio.

EDIT: non vedo davvero un motivo per cui devi avvolgere le tue classi C ++ usando le interfacce C - questo è fatto dietro le quinte. Su Linux è possibile utilizzare librerie condivise senza alcuna gestione speciale. Su Windows, tuttavia, è necessario ___ declspec (esportazione) e ___ declspec (importazione).

Migliora il riutilizzo anche se non ce ne saranno? Non sembra un argomento forte.

La modularità e la testabilità del codice non devono necessariamente dipendere dall'unità di distribuzione finale. Mi aspetto che il collegamento sia una decisione tardiva.

Se davvero hai un risultato da consegnare e non prevedi mai alcun cambiamento a quello, allora sembra eccessivo e inutile complessità da consegnare in pezzi.

Risposta breve: no.

Risposta più lunga: le librerie dinamiche non aggiungono nulla da aggiungere ai test, alla modularità o al riutilizzo che non possono essere eseguiti altrettanto facilmente in un'app monolitica. L'unico vantaggio che mi viene in mente è che può forzare la creazione di un'API in un team che non ha la disciplina per farlo da solo.

Non c'è nulla di magico in una biblioteca (dinamica o meno). Se disponi di tutto il codice per creare un'applicazione e le librerie assortite, puoi compilarlo con la stessa facilità in un unico eseguibile.

In generale, abbiamo scoperto che i costi della gestione delle librerie dinamiche non ne valgono la pena, a meno che non vi sia un bisogno irresistibile (librerie in più applicazioni, necessità di aggiornare un numero di applicazioni senza ricompilare, consentendo all'utente di aggiungere funzioni all'applicazione).

Analizzare gli argomenti del collega

Se crede che la suddivisione del codice in librerie condivise migliorerà la modularità, la testabilità e il riutilizzo del codice, suppongo che ciò significhi che credi che tu abbia qualche problema con il tuo codice e che l'applicazione di una "libreria condivisa". l'architettura lo correggerà.

Modularità?

Il tuo codice deve avere interdipendenze indesiderate che non si sarebbero verificate con una separazione più chiara tra "codice libreria" e " codice usando il codice libreria " ;.

Ora, questo può essere ottenuto anche attraverso librerie statiche.

Test?

Il tuo codice potrebbe essere testato meglio, magari costruendo unit test per ciascuna libreria condivisa separata, automatizzata ad ogni compilation.

Ora, questo può essere ottenuto anche attraverso librerie statiche.

Riutilizzo del codice?

Il tuo collega vorrebbe riutilizzare un po 'di codice che non è esposto perché nascosto nelle fonti della tua applicazione monolitica.

Conclusione

I punti 1 e 2 possono ancora essere raggiunti con le librerie statiche. Il 3 renderebbe obbligatorie le librerie condivise.

Ora, se hai più di una profondità di collegamento delle librerie (sto pensando di collegare insieme due librerie statiche che sono state già compilate collegando le altre librerie), questo può essere complesso. Su Windows, questo porta all'errore di collegamento poiché alcune funzioni (di solito le funzioni di runtime C / C ++, quando collegate staticamente) sono referenziate più di una volta e il compilatore non può scegliere quale funzione chiamare. Non so come funzioni su Linux, ma suppongo che potrebbe accadere anche questo.

Analizzare i propri argomenti

I tuoi argomenti sono in qualche modo distorti:

Onere della compilazione / collegamento delle librerie condivise?

L'onere della compilazione e del collegamento a librerie condivise, rispetto alla compilazione e al collegamento a librerie statiche è inesistente. Quindi questo argomento non ha valore.

Caricamento / scaricamento dinamico?

Il caricamento / scaricamento dinamico di una libreria condivisa potrebbe essere un problema in un caso d'uso molto limitato. In casi normali, il sistema operativo carica / scarica la libreria quando necessario senza il tuo intervento e, comunque, i tuoi problemi di prestazioni risiedono altrove.

Esporre il codice C ++ con interfacce C?

Per quanto riguarda l'utilizzo di un'interfaccia con funzione C per il tuo codice C ++, non riesco a capire: hai già collegato librerie statiche con un'interfaccia C ++. Il collegamento di librerie condivise non è diverso.

Avresti un problema se avessi compilatori diversi per produrre ciascuna libreria della tua applicazione, ma non è così, dato che hai già collegato staticamente le tue librerie.

Un singolo file binario è più semplice?

Hai ragione.

Su Windows, la differenza è trascurabile, ma esiste ancora il problema di DLL Hell , che scompare se aggiungi la versione ai nomi della libreria o lavori con Windows & nbsp; XP.

Su Linux, oltre al problema di Windows di cui sopra, hai il fatto che per impostazione predefinita, le librerie condivise devono essere in alcune directory predefinite di sistema per essere utilizzabili, quindi dovrai copiarle lì al momento dell'installazione (che può essere una seccatura ...) o modificare alcune impostazioni dell'ambiente predefinite (che può essere anche una seccatura ...)

Conclusione: chi ha ragione?

Ora, il tuo problema non è " è il mio collega ha ragione? " ;. Egli è. Anche tu come sei.

Il tuo problema è:

  1. Cosa vuoi veramente ottenere?
  2. Vale la pena il lavoro necessario per questo compito?

La prima domanda è molto importante, poiché mi sembra che i tuoi argomenti e quelli del collega siano di parte per portare alla conclusione che sembra più naturale per ognuno di voi.

Inseriscilo in un'altra formulazione: ognuno di voi sa già quale dovrebbe essere la soluzione ideale (secondo ciascun punto di vista) e ognuno di voi impila argomenti per raggiungere questa soluzione.

Non c'è modo di rispondere a questa domanda nascosta ...

^ _ ^

Effettua una semplice analisi costi / benefici: hai davvero bisogno di modularità, testabilità e riutilizzo? Hai tempo da dedicare al refactoring del tuo codice per ottenere queste funzionalità? Soprattutto, se si esegue il refactoring, i benefici ottenuti giustificheranno il tempo impiegato per eseguire il refactoring?

A meno che tu non abbia problemi con i test ora, ti consiglio di lasciare l'app così com'è. La modularizzazione è ottima, ma Linux ha la sua versione di "inferno DLL" (vedi ldconfig ) e hai già indicato che il riutilizzo non è una necessità.

Se stai ponendo la domanda e la risposta non è ovvia, rimani dove sei. Se non sei arrivato al punto in cui la creazione di un'applicazione monolitica richiede troppo tempo o è troppo doloroso per il tuo gruppo lavorare insieme, allora non c'è motivo convincente per passare alle librerie. Puoi creare un framework di test che funzioni sui file dell'applicazione se vuoi così com'è o puoi semplicemente creare un altro progetto che utilizza gli stessi file, ma collegare un'API di test e creare una libreria con quello.

Ai fini della spedizione, se vuoi creare librerie e spedire un grosso eseguibile, puoi sempre collegarti staticamente a loro.

Se la modularità aiuterebbe con lo sviluppo, cioè stai sempre facendo testa ad altri sviluppatori per le modifiche ai file, allora le librerie potrebbero aiutare, ma non è nemmeno una garanzia. L'uso di una buona progettazione del codice orientato agli oggetti sarà di aiuto indipendentemente.

E non c'è motivo di racchiudere alcuna funzione con le interfacce di tipo C necessarie per creare una libreria a meno che non si desideri che sia richiamabile da C.

Le librerie condivise hanno il loro mal di testa, ma penso che le librerie condivise siano la strada giusta per andare qui. Direi che nella maggior parte dei casi dovresti essere in grado di rendere parti della tua applicazione modulari e riutilizzabili altrove nella tua attività. Inoltre, a seconda delle dimensioni di questo eseguibile monolitico, potrebbe essere più semplice caricare un set di librerie aggiornate anziché un file di grandi dimensioni.

IMO, le biblioteche in generale portano a un codice migliore, a un codice più testabile e consentono di creare progetti futuri in modo più efficiente perché non stai reinventando la ruota.

In breve, sono d'accordo con il tuo collega.

Su Linux (e Windows) è possibile creare una libreria condivisa utilizzando C ++ e non è necessario caricarla utilizzando le esportazioni della funzione C.

Cioè, costruisci classA.cpp in classA.so e costruisci classB.cpp in classB (.exe) che collega a classA.so. Tutto quello che stai veramente facendo è dividere la tua applicazione in più file binari. Questo ha il vantaggio che sono più veloci da compilare, più facili da gestire e puoi scrivere applicazioni che caricano solo quel codice di libreria per i test.

Tutto è ancora C ++, tutto collega, ma il tuo .so è separato dalla tua applicazione collegata staticamente.

Ora, se si desidera caricare un oggetto diverso in fase di runtime (ovvero, non si sa quale caricare fino al runtime), è necessario creare un oggetto condiviso con c-export, ma si sarà anche caricamento manuale di tali funzioni; non saresti in grado di usare il linker per fare questo per te.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top