Presque tout peut être analysé en termes de coûts et d'avantages, et je pense que cela s'applique ici.
Les avantages évidents de la première option sont qu'elle minimise le travail à court terme et les chances de casser quelque chose en réécrivant le code de travail. Le coût évident est qu'il introduit une incohérence dans la base de code. Lorsque vous effectuez une opération X, cela se fait d'une manière dans certaines parties du code et d'une manière différente dans une autre partie du code.
Pour la deuxième approche, vous avez déjà noté l'avantage évident: la cohérence. Le coût évident est que vous devez vous efforcer de travailler d'une manière que vous auriez autrement abandonnée il y a des années, et le code reste toujours illisible.
Pour la troisième approche, le coût évident est simplement d'avoir à faire beaucoup plus de travail. Un coût moins évident est que vous pouvez casser des choses qui fonctionnaient. Cela est particulièrement probable si (comme c'est souvent le cas) l'ancien code a des tests inadéquats pour s'assurer qu'il continue de fonctionner correctement. L'avantage évident est que (en supposant que vous réussissiez), vous disposez d'un nouveau code agréable et brillant. Parallèlement à l'utilisation de nouvelles constructions de langage, vous avez la possibilité de refactoriser la base de code, qui apportera presque toujours des améliorations en soi, même si vous utilisez toujours le langage tel qu'il existait lors de son écriture - ajoutez de nouvelles constructions qui rendent le travail plus facile, et il pourrait bien être une victoire majeure.
Un autre point majeur cependant: en ce moment, il semble que ce module ait eu une maintenance minimale pendant longtemps (même si le projet dans son ensemble est maintenu). Cela tend à indiquer qu'il est assez bien écrit et relativement exempt de bogues - sinon, il aurait probablement subi plus de maintenance dans l'intervalle.
Cela conduit à une autre question: quelle est la source du changement que vous apportez maintenant? Si vous corrigez un petit bogue dans un module qui, dans l'ensemble, répond toujours bien à ses exigences, cela tendrait à indiquer que le temps et les efforts de refactorisation de l'ensemble du module seront probablement largement gaspillés - au moment où quelqu'un doit jouer avec encore une fois, ils pourraient bien se trouver à peu près dans la même position que vous, maintenant, en maintenant un code qui ne répond pas aux attentes "modernes".
Il est également possible, cependant, que les exigences aient changé, et vous travaillez sur le code pour répondre à ces nouvelles exigences. Dans ce cas, il y a de fortes chances que vos premières tentatives ne répondent pas réellement aux exigences actuelles. Il y a également une plus grande chance que les exigences subissent quelques cycles de révision avant de se stabiliser à nouveau. Cela signifie que vous êtes beaucoup plus susceptible de faire un travail important dans ce module à court (relativement) court terme, et beaucoup plus susceptible de faire des changements dans le reste du module, pas seulement dans le seul domaine que vous connaissez bien maintenant. Dans ce cas, la refactorisation de l'ensemble du module est beaucoup plus susceptible d'avoir des avantages tangibles à court terme qui justifient le travail supplémentaire.
Si les exigences ont changé, vous devrez peut-être également examiner le type de changement impliqué et les raisons de ce changement. Par exemple, supposons que vous modifiiez Git pour remplacer son utilisation de SHA-1 par SHA-256. Il s'agit d'un changement dans les exigences, mais la portée est clairement définie et assez étroite. Une fois que vous l'avez fait stocker et utiliser SHA-256 correctement, il est peu probable que vous rencontriez d'autres changements qui affectent le reste de la base de code.
Dans l'autre sens, même quand cela commence petit et discret, un changement à une interface utilisateur a tendance à monter en flèche, donc ce qui a commencé comme "ajouter une nouvelle case à cocher à cet écran" finit plus comme: "changer cette interface utilisateur fixe pour prendre en charge les modèles définis par l'utilisateur, les champs personnalisés, les schémas de couleurs personnalisés, etc. "
Pour le premier exemple, il est probablement plus judicieux de minimiser les changements et d'errer du côté de la cohérence. Pour ces derniers, le refactoring complet est beaucoup plus susceptible de porter ses fruits.