2010-08-12 5 views
9

Ok, non sto provando a iniziare una guerra di fiamma qui, e so che l'argomento tra i linguaggi statici e dinamici è stato troncato molte volte, anche qui. Ma ho una domanda molto pratica che spero che qualcuno qui possa fare luce. Ci scusiamo per la lunghezza, ma questa non è una domanda semplice, probabilmente non è una risposta semplice.Refactoring con linguaggio digitato dinamicamente

Ruby, PHP e Javascript sono lingue molto popolari al giorno d'oggi, e hanno un sacco di persone che li difendono e sostengono che essere digitati dinamicamente non trattiene lo sviluppatore. Sono nuovo di questi linguaggi e vorrei iniziare a usarli per progetti più grandi, ma qui c'è uno scenario di refactoring di base che appare tutto il tempo al lavoro (lavoro == C#), e mi chiedo quale sarà l'approccio in Ruby: ho scelto Ruby perché è OO.

Ok, sto usando Ruby e costruisco un oggetto Cliente. Ha metodi per caricare/salvare/cancellare dal database. È buono e le persone lo usano. Aggiungo altri metodi per altre cose e le persone lo usano di più. Aggiungo un metodo per calcolare la cronologia degli ordini in base ad alcuni parametri. Ormai questa classe viene utilizzata in tutto il sistema. Quindi, un giorno decido di cambiare i parametri sul metodo GetOrderHistory. Così ho:

  • aggiungo i nuovi parametri per il metodo
  • riscrivere il codice del metodo di utilizzare i nuovi parametri
  • cambiamento del codice client che avevo in mente di passare i nuovi parametri e utilizzare questo modificato metodo

Ma ora che cosa? Ho dozzine/centinaia/whoknows quanti altri posti nel sistema che devono essere cambiati. In un linguaggio OO dinamico come Ruby o Javascript, come potrei fare questo?

Fuori della parte superiore della mia testa, non sapendo rubino molto bene, mi vengono in mente due risposte muti:

  1. 100% di copertura di codice. Esamino l'intera app e ogni volta che si rompe vedo se è quel metodo e lo risolvo
  2. Trova e sostituisci. Io uso la ricerca di testo per cercare quel metodo. Ma potrei avere altri oggetti con gli stessi nomi di metodo.

Quindi c'è una buona risposta a questo? Sembra che l'IDE abbia delle difficoltà. Se avessi codice come

c = Customer.new 

sarebbe in grado di capirlo, ma se si tratta di

c= SomeFunctionThatProbablyReturnsACustomerButMightReturnOtherThings() 

Così che cosa approccio esperti si rubino prendere in questo caso?

+0

Sono abbastanza sicuro che il refactoring non dovrebbe rompere i contratti esistenti ... – CurtainDog

+0

@CurtainDog, che dire del rinominare una funzione privata all'interno di una libreria? – Toskan

+0

un altro buon esempio è rubino e pitone. Posso essere gentile a ricordarti che né rubino né pitone si attengono a ciò che hai appena detto quando rilasci nuove versioni? – Toskan

risposta

3

Uno degli argomenti forti che sentirete è che si dovrebbe scrivere i test in anticipo. Questo, in teoria, ti mostrerebbe esattamente dove deve cambiare l'app nel caso in cui qualcosa cambi.

Ma questo è solo il top dell'iceberg. Ruby è stato progettato tenendo conto di alcune linee guida, come le funzioni brevi, espressive, la suddivisione delle responsabilità nei moduli, la non ripetizione del codice (DRY), il principio della sorpresa minima, ecc; più una serie di pratiche raccomandate, come testare prima, passare parametri come hash-options, usare metaprogramming con saggezza, ecc. Sono sicuro che anche altri linguaggi dinamici fanno altrettanto.

Se c non è un cliente, quindi almeno mi aspetto atto come uno. Gli IDE possono cercare la digitazione anatra, che è più flessibile rispetto alla verifica di un'istanza di una particolare classe.

Alcuni IDE (almeno Rubymine) consultano anche le convenzioni. Ad esempio, nelle applicazioni Rails, Rubymine va al file dello schema e aggiunge le proprietà del modello nel database come metodi. Riconosce anche le associazioni (has_many, belongs_to, ecc.) E aggiunge dinamicamente i metodi corrispondenti, che Rails genera sotto il cofano.

Ora, questo praticamente riduce il bisogno di refactoring, almeno lo mantiene al minimo. Ma certamente lo non lo risolve. E non penso che possa essere risolto.

+0

buone intuizioni, grazie. L'idea di battitura delle anatre è particolarmente interessante, ho intenzione di approfondire l'argomento. Inoltre, in un altro post qui, qualcuno ha citato Flow Analysis, che ritengo sia una cosa precompilabile più intelligente che possa capire quale possa essere il tipo di runtime. Sembra complicato però ... – LoveMeSomeCode

+1

anche, per non essere polemico, ma l'idea dei test mi infastidisce. Non gli stessi test, perché credo che tutto il buon codice dovrebbe avere test unitari accurati, ma l'idea della verbosità. Un sacco di gente sosterrà che i linguaggi dinamici sono meno prolissi perché non sono necessari descrittori di tipi, ma quando le persone parlano di sicurezza del tipo accennano alla necessità di test aggiuntivi, che annulla il codice sintetico che hanno scritto . solo un'osservazione generale ... – LoveMeSomeCode

+0

beh, mi dispiace ... ma non potresti, e sono serio, sostenere che questi concetti dovrebbero applicarsi in tutti i linguaggi di programmazione? Non essere in grado di refactoring è davvero un grosso problema. – Toskan

1

Probabilmente questa non sarà la migliore risposta alla tua domanda, ma io tendo ad apprezzare i metodi di progettazione per accettare un hash per coprire i cambiamenti futuri.

Esempio:

def my_method(options = {}) 
    if options[:name] 
    ... 
    end 
end 

Penso che un sacco di gente più avanzate di Ruby apparirebbe ad attuare una sorta di modello Metaprogrammazione.

Altre opzioni possono includere il superamento del metodo in una sottoclasse per eseguire la funzionalità desiderata.

Oppure, come su ...

def get_order_history(required_param, options = []) 

    @required_param = required_param 

    if options[:do_something_else] 
    result = other_method(options[:do_something_else]) 
    else 
    result = ... 
    end 

    result  

end 

def other_method(something_else) 
    ... 
end 
+0

La sottoclasse è un buon punto. Questa è una delle opzioni che ho preso in considerazione dopo l'invio, ma poi ho pensato: "Cosa succede se il metodo sta davvero cambiando, come a causa di un cambiamento dello schema db, e non hai affatto bisogno del vecchio codice, e tutti hanno bisogno di usa il nuovo metodo? ' – LoveMeSomeCode