Argomenti della funzione di digitazione dinamica: come mantenere elevata la leggibilità?

7

Newbie che scrive dinamicamente qui, sperando in alcune parole avvizzite di saggezza.

Sono curioso di sapere se esiste una serie di best practice per trattare gli argomenti delle funzioni (e siamo onesti, le variabili in generale) in linguaggi tipizzati dinamicamente come Javascript. Il problema che mi imbatto spesso riguarda la leggibilità del codice: sto osservando una funzione che ho scritto qualche tempo fa e non ho idea di cosa sia effettivamente la struttura delle variabili dell'argomento. Di solito è ok al momento dello sviluppo del nuovo codice: tutto è fresco nella mia testa, ogni variabile e parametro ha senso perché li ho appena scritti. Una settimana dopo? Non così tanto.

Ad esempio, supponiamo che sto cercando di scricchiolare una serie di dati sulle sessioni utente su un sito Web e di ricavarne qualcosa di utile:

var crunchSomeSessionData = function(sessionsMap, options) {
    [...]
}

Ignorare il fatto che il nome della funzione non sia utile - che ovviamente è un grosso problema - in realtà non so nulla su quale sia la struttura di sessionMap o delle opzioni. Ok .. Ho k / v accoppiare l'oggetto sessionMap, dato che si chiama Map, ma il valore è un primitivo, un array, un altro hash di roba? Cosa sono le opzioni? Un array? Una stringa separata da spazi bianchi?

Ho alcune opzioni:

  • chiarire la struttura esattamente nell'intestazione del commento per la funzione. Il problema è che ora devo mantenere il codice in due punti.
  • avere un nome il più utile possibile. per esempio. userIdToArrayOfTimestampsMap o anche avere qualche tipo di dialetto pseudo-ungherese per la denominazione delle variabili che solo io parlo che spiega quali sono i tipi e come sono nidificati. Questo porta a un codice veramente prolisso, e sono un fan del mantenimento di materiale inferiore a 80 punti.
  • interrompe le funzioni finché non passo sempre in giro primitive o raccolte di primitive. Immagino che potrebbe funzionare, ma probabilmente finirei con micro-funzioni che hanno al massimo una o due righe, funzioni che esistono solo allo scopo di leggibilità. Ora devo saltare tutto il file e ricomporre la funzione nella mia testa, il che ha reso la leggibilità ancora peggiore.
  • alcune lingue offrono la destrutturazione, che in qualche misura può quasi essere considerata una documentazione extra per ciò che il tipo di argomento sta per contenere.
  • potrebbe creare una "classe" per il tipo specifico di oggetto, anche se non farebbe un'enorme differenza in un linguaggio prototipale come JS, e probabilmente aggiungerebbe più spese di manutenzione del necessario. In alternativa, se disponibile, si può provare a usare i protocolli, forse qualcosa sulla falsariga di deftype / defrecord di Clojure ecc.

Nel mondo tipizzato staticamente, questo non è un problema. Ad esempio in C # si ottiene:

public void DoStuff(Dictionary<string, string> foo) {[...]};

Ok, è facile, so esattamente cosa sto ricevendo, non c'è bisogno di leggere l'intestazione della funzione, o tornare al chiamante e capire cosa sta architettando ecc.

Qual è la soluzione qui? Tutte le persone che si sviluppano in lingue digitate dinamicamente sono continuamente sconvolte dai tipi che ricevono le loro subroutine? Esistono strategie di mitigazione?

    
posta Alexandr Kurilin 25.04.2013 - 07:01
fonte

3 risposte

1

Penso che molti dei problemi che stai affrontando possano essere risolti con un'appropriata denominazione delle variabili e il contenuto del metodo. Per la maggior parte dovrebbe essere ovvio quali sono i tipi di parametri basati sui nomi e il contenuto del metodo. Anche la documentazione aiuta.

Ad esempio:

function getSum(arr) {
    var sum = 0;
    arr.forEach(arr, function(item) {
        sum += item;
    });

    return sum;
}

Solo dal nome della funzione e da come è scritto dovrebbe essere implicito che getSum prende una serie di numeri e restituisce un numero.

Vediamo un altro esempio che non ha senso irl ma dovrebbe avere un senso a ciò che sta facendo.

var crunchSomeSessionData = function(sessionsMap) {
    var browsers = {};

    Object.keys(sessionsMap).forEach(function(key) {
        var session = sessionsMap[key],
            browser = session.getBrowser();

        if(!browsers[browser]) {
            browsers[browser] = [];
        }

        browsers[browser].push(session.getUserId());
    });

    return browsers;
}

Senza una documentazione adeguata (irl questo sarebbe documentato) puoi ancora vedere che crunchSessionData prende un oggetto di istanze di Session, quelle istanze hanno un metodo getBrowser e getUserId. Restituisce un oggetto disattivato dal browser che ha una matrice di ID utente attualmente presenti su quel browser.

crunchSomeSessionData({
    213j123j123j123j13: {browser: 'chrome', userId: 'pllee'},
    fawefjioawejfwoeiw: {browser: 'ie', userId: 'grandpa'}
})
>> {chrome: ['pllee'], ie: ['grandpa']}

Suggerirei di capire bene come la digitazione dinamica può essere letta, leggere un codice open source che non è molto documentato e vedere se è possibile seguire ciò che sta accadendo. In tal caso, inizia a utilizzare i loro schemi di progettazione. Puoi controllare la semplice libreria di timing delle prestazioni che ho scritto link . È molto piccolo e la maggior parte dei metodi non sono documentati. Il codice non è perfetto ma potrebbe essere un buon esempio. Dopo averlo guardato o usato per mesi, il codice ha ancora senso per me, ma l'ho scritto:)

    
risposta data 26.04.2013 - 08:40
fonte
1

Forse prova a scriverlo di più in stile OOP. Ad esempio, anziché:

var crunchSomeSessionData = function(sessionsMap, options) {
    [...]
}

perché non puoi farlo

session.crunchData(options)

dove la sessione è l'oggetto che hai creato. Sarai in grado di dare un'occhiata al costruttore per sapere esattamente come viene creata la sessione e tutti i tuoi problemi dovrebbero andare via

    
risposta data 26.04.2013 - 12:20
fonte
1

Qualsiasi codice dovrebbe essere documentato con informazioni sufficienti per capirlo. Ciò include informazioni sui tipi di variabili, se necessario (e anche nelle lingue tipizzate staticamente, potresti aver bisogno di più informazioni di quelle fornite solo dalla parola chiave type).

Quando ti abitui a lavorare con un linguaggio tipizzato dinamicamente, scoprirai che il tipo di una variabile è spesso autoesplicativo in base al suo utilizzo. Ma se no, aggiungi commenti per chiarirlo.

Per quanto riguarda la tua preoccupazione che tali commenti aggiungano duplicazione (e possibilmente infrangono un principio come DRY), tale preoccupazione si applicherebbe a qualsiasi commento . Qualsiasi documentazione aggiunge intrinsecamente una certa quantità di duplicazione e deve essere mantenuta in modo che corrisponda al codice. Ma quando aiuta a rendere comprensibile il codice, i benefici superano i costi.

Inoltre, si noti che la maggior parte delle altre soluzioni prevede la creazione di tanto (o più) elementi aggiuntivi. Una classe avrebbe bisogno di una definizione di classe che sia grande almeno quanto i commenti. (Naturalmente, fare una lezione potrebbe essere utile per altri motivi, ma non evitare di risolvere ciò con i commenti solo perché aggiungono linee extra al tuo codice.)

I commenti dovrebbero essere fatti solo quando è necessario comprendere il codice, comunque. Odio vedere un codice come questo, che in realtà è una duplicazione inutile:

//crunchSomeSessionData - A function that crunches some session data.
//
//sessionsMap - A map containing the sessions and their data that we want to crunch.
//user - The user for whose sessions we want to crunch data
function crunchSomeSessionData(sessionsMap, user) {
    [...]
}
    
risposta data 26.04.2013 - 12:41
fonte