Ho bisogno di consigli e feedback sul design del mio codice

1

Sto cercando feedback sul design del mio programma.

Ho una chiamata allo script shell function.sh che definisce molte funzioni di aiuto. Il mio intento è quello di utilizzare quelle funzioni di bash definite in functions.sh in un programma C. Lo sto facendo in modo che non debba riscrivere di nuovo la funzionalità di bash (in functions.sh) in C. Voglio usare una libreria comune per le funzioni di cui ho bisogno (che è functions.sh).

Ecco il mio codice C e functions.sh
Codice C:

#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>

void shellCall(char * command)
{
    int status, commandexitcode=0;
    if(command == NULL)
    {
        printf("NULL command string sent\n");
        exit(1);
    }

    status = system(command);

    if(status == -1)
    {
        printf("Error during call, value %d\n", status);
        exit(1);   
    }

    if (WIFEXITED(status)) 
    {
        commandexitcode =  WEXITSTATUS(status);
        if (commandexitcode != 0)
        {
            printf("non zero exit code: %d\n", commandexitcode);
            exit(1);
        }
    } 

    else 
       if (WIFSIGNALED(status))
    ...
}


int main(int argc,char **argv)
{
    char  command[100]; //command
    int i = 0;

    for (i = 1 ; i <= 10 ; i++)
    {
        sprintf( command, "source $PWD/functions.sh ; i=%d ; myfunc %d", i,i );
        shellCall(command);      
    }
}

functions.sh:

#!/bin/sh
# functions.sh

myfunc()
{
    echo "I received $1"
}

Si noti che ho solo mostrato un esempio molto semplice di come sto usando le funzioni in functions.sh. In realtà functions.sh ha molte funzioni, alcune delle quali implementano una logica decente.

Le mie domande - Ho bisogno di feedback sui seguenti aspetti.

  1. È una cattiva pratica di programmazione (qualcosa che farà impazzire gli sviluppatori esperti e senior quando vedono questo) di usare le chiamate system () per chiamare le funzioni in functions.sh come ho fatto io?

  2. Se si tratta di una cattiva pratica, quali sono le ragioni (tecniche e non) per le quali è considerata una cattiva pratica di programmazione?

  3. Quali modifiche dovrei apportare al mio codice C in modo che gli sviluppatori esperti e senior lo trovino accettabile?

posta user80195 01.02.2013 - 21:24
fonte

2 risposte

2

Chiamare 'system ()' ha un'enorme quantità di overhead. Il sistema operativo deve creare una nuova shell per ciascuna di queste chiamate. Complimenti per aver fatto il controllo degli errori sul valore di ritorno di system (), ma puoi vedere quanto è complesso il tuo programma. Inoltre, è necessario aggiungere ancora più controllo degli errori. È necessario verificare che gli script della shell siano dove si pensa che siano prima di chiamarli con system (). Se non sono dove ti aspetti che siano, o hai le autorizzazioni sbagliate, il tuo programma fallirà con messaggi ostili all'utente.

Stai rendendo più complessa la distribuzione e la configurazione del tuo programma. Non solo devi distribuire un binario, ma devi anche distribuire gli script della shell e assicurarti che finiscano nella directory corretta.

Non spieghi perché lo stai facendo in questo modo, ma in assenza di altre informazioni ti suggerirei di trasformare l'intera cosa dentro e fuori. Scrivi uno script di shell che richiami alcuni programmi C per svolgere qualsiasi lavoro intensivo dal punto di vista computazionale.

    
risposta data 01.02.2013 - 23:27
fonte
1

I am writing a C program because bash shell does not allow dynamic memory allocation and I need that for my logic ( although I have not shown that above).

Ad un livello elevato, questo sembra essere un conglomerato di un C e script di shell in cui uno sta controllando l'altro - la natura esatta di dove esiste la logica non è ben definita nell'esempio.

L'unico classico esempio di tale progetto è uno script di shell (con la logica dell'applicazione in esso) che sta richiamando un numero di programmi C compilati che fanno ciò che lo script di shell non può fare. In una certa misura questo è il 99% di tutti gli script di shell - invoca qualcosa, reindirizzalo a grep, esegui il pipe per tagliare, imposta una variabile da quella, invoca qualcosa in base a tale variabile, pipe che restituisce in awk e sed, ecc ...

Un design del genere è abbastanza ragionevole e comune e nulla di cui uno può essere estremamente offeso.

Un altro approccio è dove l'applicazione è un singolo programma conforme che sta facendo tutto ciò che sta facendo (ascoltando le connessioni di rete, facendo chugging a bit di calcolo intensivi, formattando xml e gettandolo su una coda di messaggi, visualizzando una GUI, ecc. ..). A volte questa applicazione si trova ad avere bisogno di interagire con il sistema sottostante - ad esempio, nel tentativo di mettere un messaggio su una coda potrebbe aver scoperto che quel demone è morto e ha bisogno di riavviarlo - impostare un gruppo di variabili d'ambiente, sudo / etc / init.d / amqd start. Mentre è possibile che questo programma compilato imponga invece una copia di se stesso che modifica il suo ambiente e fa chiamate di sistema, che possono essere costose per l'applicazione compilata e sono probabilmente soggette a più bug di qualcosa che è più facile da capire e mantenere. È perfetto anche per questo modello e mentre alcune persone possono lamentarsi di più parti dell'applicazione, non è un reato grave.

Esaminiamo nuovamente la citazione e inseriamo questo nel contesto dell'esempio di codice nella domanda.

I am writing a C program because bash shell does not allow dynamic memory allocation and I need that for my logic ( although I have not shown that above).

Sembra che l'applicazione nel suo complesso abbia la sua divisione logica tra le funzioni in functions.sh e il codice C compilato. Esiste una macchina di stato (di sorta) che esiste nella combinazione dei due pezzi. La logica dell'applicazione non sembra esistere solo in una parte o nell'altra. Il programma compilato invoca uno script di shell con una funzione che viene quindi eseguita e il suo output viene utilizzato per determinare quale shell eseguire successivamente. Il programma compilato esiste come archivio dati dinamico per i programmi della shell.

Design scadente .

Le modifiche apportate in uno influenzano le modifiche nell'altro. Non esiste un singolo punto di responsabilità per la logica. Mantenere due gruppi di lingue con l'interdipendenza tra i due può essere difficile per mantenere in ordine, testare e implementare.

Sono un fan del cammello. Questo colorerà il mio suggerimento.

Any shell script longer than 10 lines should be rewritten in perl.

La giustificazione originale per la progettazione split era che bash non aveva prestazioni accettabili con la memoria degli array dinamici. Ok, quindi non usare bash. Tuttavia, sembra che ci sia un certo desiderio di interagire con il sistema a un livello superiore rispetto a C. Ok, quindi non usare C. Usa perl (o python, o se devi, ruby).

Queste lingue eccellono nel complesso processo che gli script di shell hanno difficoltà a fare senza dover andare a un programma C. In molti casi, si può fare tutto ciò che è tradizionalmente fatto in shell (tagliare, grep, awk, sed, tr, aprire il file, scrivere su file, ecc ...) senza dover bifare un altro processo. Inoltre, avere una singola applicazione che contiene tutta la logica al suo interno è un design superiore rispetto al tentativo di dividerlo tra due dissimili.

Sì, vuol dire riscrivere functions.sh in perl (anche se al momento, la totalità del codice fornito è il print incorporato). Significa anche che, una volta terminato, avrai una libreria di chiamate in un bel modulo autonomo.

    
risposta data 03.02.2013 - 05:44
fonte