Quasi tutto può essere analizzato in termini di costi e benefici, e penso che questo si applichi qui.
Gli ovvi vantaggi della prima opzione sono che minimizza il lavoro a breve termine e minimizza le possibilità di rompere qualcosa riscrivendo il codice di lavoro. Il costo evidente è che introduce incoerenza nella base di codice. Quando si esegue un'operazione X, viene eseguita in un modo in alcune parti del codice e in un modo diverso in una parte diversa del codice.
Per il secondo approccio, hai già notato l'ovvio vantaggio: coerenza. Il costo ovvio è che devi piegare la mente per lavorare in modi che altrimenti potresti aver abbandonato anni fa, e il codice rimane costantemente illeggibile.
Per il terzo approccio, il costo evidente è semplicemente dover fare molto più lavoro. Un costo meno ovvio è che potresti rompere le cose che funzionavano. Ciò è particolarmente probabile se (come spesso accade) il vecchio codice presenta test inadeguati per garantire che continui a funzionare correttamente. L'ovvio vantaggio è che (supponendo che tu lo faccia con successo) hai un nuovo codice piacevole e brillante. Oltre all'utilizzo di nuovi costrutti di linguaggio, hai la possibilità di refactoring della base di codice, che fornirà quasi sempre miglioramenti in sé, anche se hai ancora usato il linguaggio esattamente come esisteva quando è stato scritto - aggiungi nuovi costrutti che rendono il lavoro più semplice e potrebbe anche essere una vittoria importante.
Un altro punto importante: in questo momento, sembra che questo modulo abbia avuto una manutenzione minima per molto tempo (anche se il progetto nel suo complesso viene mantenuto). Ciò tende ad indicare che è abbastanza ben scritto e relativamente privo di bug - altrimenti, nel frattempo, avrebbe probabilmente subito più manutenzione.
Ciò porta a un'altra domanda: qual è la fonte del cambiamento che stai facendo ora? Se stai risolvendo un piccolo bug in un modulo che nel complesso soddisfa ancora bene i suoi requisiti, ciò tenderebbe ad indicare che il tempo e gli sforzi per il refactoring dell'intero modulo saranno probabilmente sprecati in gran parte - quando qualcuno dovrà fare confusione anche in questo caso, potrebbero trovarsi all'incirca nella stessa posizione in cui ti trovi ora, mantenendo un codice che non soddisfa le aspettative "moderne".
È anche possibile, tuttavia, che i requisiti siano cambiati e si sta lavorando sul codice per soddisfare tali nuovi requisiti. In questo caso, è probabile che i tuoi primi tentativi non soddisfino effettivamente i requisiti attuali. Esiste anche una probabilità sostanzialmente maggiore che i requisiti subiscano alcuni cicli di revisione prima che si stabilizzino nuovamente. Ciò significa che è molto più probabile che svolgiate un lavoro significativo in questo modulo nel (relativamente) breve termine, e molto più probabilità di apportare modifiche in tutto il resto del modulo, non solo nell'area che conoscete bene adesso. In questo caso, è molto più probabile che il refactoring dell'intero modulo abbia benefici tangibili a breve termine che giustificano il lavoro extra.
Se i requisiti sono cambiati, potrebbe anche essere necessario esaminare quale tipo di cambiamento è coinvolto e cosa sta guidando quel cambiamento. Ad esempio, supponiamo che stiate modificando Git per sostituire il suo uso di SHA-1 con SHA-256. Si tratta di una modifica dei requisiti, ma l'ambito è chiaramente definito e abbastanza limitato. Dopo averlo archiviato e utilizzato correttamente SHA-256, è improbabile che si verifichino altre modifiche che influiscono sul resto della base di codice.
Nella direzione opposta, anche quando inizia in modo discreto e discreto, una modifica a un'interfaccia utente ha la tendenza a sovrapporsi, quindi ciò che è iniziato come "aggiungi una nuova casella di controllo a questa schermata" finisce più come: "cambia questa IU fissa per supportare modelli definiti dall'utente, campi personalizzati, combinazioni di colori personalizzate, ecc. "
Per il primo esempio, probabilmente ha più senso ridurre al minimo le modifiche e gli errori dal punto di vista della coerenza. Per quest'ultimo, il refactoring completo ha molte più probabilità di ripagare.