C'est généralement une bonne chose de le faire chaque fois que possible, mais j'aime à penser à ce genre de travail non pas comme des «étapes», mais comme des sous-tâches .
Une sous-tâche est une unité de travail spécifique qui peut être effectuée: elle a une responsabilité spécifique et des entrées et des sorties définies (pensez au "S" dans SOLID ). Une sous-tâche n'a pas besoin d'être réutilisable: certaines personnes ont tendance à penser "Je n'aurai jamais à appeler cela depuis autre chose, alors pourquoi l'écrire en fonction?" mais c'est une erreur.
J'essaierai également de décrire les avantages et la façon dont cela s'applique aux fonctions imbriquées (fermetures) par rapport à une autre fonction de la classe. De manière générale, je recommande de ne pas utiliser de fermetures sauf si vous en avez spécifiquement besoin (il existe de nombreuses utilisations, mais la séparation du code en morceaux logiques n'en fait pas partie).
Lisibilité.
Plus de 200 lignes de code procédural (corps d'une fonction) sont difficiles à lire. Les fonctions de 2 à 20 lignes sont faciles à lire. Le code est pour les humains.
Imbriqués ou non, vous bénéficiez principalement de la lisibilité, à moins que vous n'utilisiez beaucoup de variables de la portée parent, auquel cas cela peut être tout aussi difficile à lire.
Limiter la portée variable
Le fait d'avoir une autre fonction vous oblige à limiter la portée des variables et à transmettre spécifiquement ce dont vous avez besoin.
Souvent, cela améliore également la structure du code, car si vous avez besoin d'une sorte de variable d'état d'une "étape" antérieure, vous pourriez en fait découvrir qu'il existe en fait une autre sous-tâche qui doit être écrite et exécutée en premier pour obtenir cette valeur. Ou en d'autres termes, il est plus difficile d'écrire des morceaux de code fortement couplés.
Le fait d'avoir des fonctions imbriquées vous permet d'accéder aux variables dans la portée parent depuis l'intérieur de la fonction imbriquée (fermeture). Cela peut être très utile, mais cela peut également conduire à des bogues subtils et difficiles à trouver car l'exécution de la fonction peut ne pas se produire de la manière dont elle est écrite. C'est encore plus le cas si vous modifiez des variables dans la portée parent (une très mauvaise idée, en général).
Tests unitaires
Chaque sous-tâche, implémentée une fonction (ou même une classe) est un morceau de code testable autonome. Les avantages des tests unitaires et du TDD sont bien documentés ailleurs.
L'utilisation de fonctions / fermetures imbriquées ne permet pas de tester les unités. Pour moi, c'est une rupture de marché et la raison pour laquelle vous devriez simplement une autre fonction, à moins qu'il n'y ait un besoin spécifique de fermeture.
Travailler en équipe / Conception descendante
Les sous-tâches peuvent être écrites par différentes personnes, indépendamment, si nécessaire.
Même par vous-même, il peut être utile lors de l'écriture de code d'appeler simplement une sous-tâche qui n'existe pas encore, tout en construisant la fonctionnalité principale, et de ne vous soucier de l'implémentation de la sous-tâche qu'après avoir su qu'elle obtiendra les résultats dont vous avez besoin dans un manière significative. Ceci est également appelé conception / programmation descendante.
Réutilisation du code
D'accord, donc malgré ce que j'ai dit plus tôt, il arrive parfois qu'il y ait une raison plus tard de réutiliser une sous-tâche pour autre chose. Je ne préconise pas du tout "l'astronaute de l'architecture", mais simplement qu'en écrivant du code faiblement couplé, vous pourriez finir par bénéficier plus tard de la réutilisation.
Souvent, cette réutilisation signifie une refactorisation, ce qui est parfaitement attendu, mais la refactorisation des paramètres d'entrée vers une petite fonction autonome est BEAUCOUP plus facile que de l'extraire d'une fonction de plus de 200 lignes plusieurs mois après son écriture, ce qui est vraiment mon point ici.
Si vous utilisez une fonction imbriquée, la réutiliser est généralement une question de refactoring dans une fonction distincte de toute façon, ce qui explique pourquoi je dirais que l'imbriqué n'est pas la voie à suivre.