Access
 sql >> Base de données >  >> RDS >> Access

Création de dépendances facultatives

Dans mon article d'hier, j'ai présenté le concept de "train de dépendance". C'est ce qui se passe lorsque vous importez une fonction à partir de votre bibliothèque de code, mais vous finissez par devoir importer plusieurs modules supplémentaires juste pour satisfaire toutes les dépendances. Vous vous retrouvez avec tout un "train" de modules de code alors que tout ce dont vous aviez besoin était un seul "siège" (fonction).

Vous vous retrouvez dans cette situation lorsque vos modules sont étroitement couplés. Alors, que pouvez-vous faire à ce sujet? Il existe plusieurs façons de gérer cette situation.

Violer "ne vous répétez pas"

Une façon de préserver le couplage lâche - qui se traduit par davantage de modules "autonomes" - consiste à créer des copies privées des fonctions du module source dans le module appelant. Cela élimine la dépendance entre les deux modules, mais cela entraîne un code répétitif.

Le concept est simple. Vous copiez la fonction à partir de son module de code principal. Vous le collez ensuite dans le module appelant mais le marquez comme privé pour éviter toute ambiguïté.

Cela a du sens dans les situations suivantes :

  • Méthodes simples sans logique complexe.
  • Procédures qui ne sont pas susceptibles de changer.
  • Lorsque la routine fait partie d'un module beaucoup plus grand et que vous n'avez besoin d'aucune des autres fonctions du module. Copier la seule fonction évite les ballonnements.

Cette approche présente les inconvénients suivants :

  • S'il existe un bogue dans la fonction copiée, vous devrez le corriger à plusieurs endroits.
  • Vous avez une duplication de code si vous finissez par importer le module source de toute façon.

Choisissez vos batailles

J'avais l'habitude d'aller très loin pour garder tous mes modules de bibliothèque de code standard complètement autonomes. Le problème était que cela entraînait de nombreuses duplications de code. La raison en est que la plupart des fonctions que je copiais vers d'autres modules pour un usage privé provenaient de modules que j'importais de toute façon dans mon application.

Un excellent exemple de cela était mes StringFunctions module. Ce module a plusieurs méthodes simples qui existent en grande partie pour rendre mon code plus lisible. Par exemple, j'ai un Conc() fonction que j'incluais en tant que fonction privée dans plus de la moitié de mes modules de bibliothèque de code.

Au fil du temps, j'ai réalisé que j'avais inclus ce StringFunctions module dans tous mes projets. Je n'introduisais jamais de nouvelle dépendance lorsque j'appelais une fonction à partir de ce module. Je perdais du temps et introduisais du code en double pour peu ou pas d'avantages.

Il y avait quelques modules de code que je pouvais supposer en toute sécurité seraient dans chaque application. Ce sont les modules avec des fonctions que j'ai le plus souvent utilisés. Ce qui signifiait que bon nombre de ces dépendances pouvaient essentiellement être ignorées.

Je maintiens maintenant une "bibliothèque standard" de modules de code que j'importe dans chaque nouveau projet au tout début. J'appelle librement les fonctions de ces modules maintenant sécurisés en sachant que je n'introduirai pas de nouvelles dépendances.

Utiliser un jeton de commentaire unique

L'un des modules de ma "Bibliothèque standard" est un module de classe (clsApp ) qui inclut des propriétés et des méthodes au niveau de l'application, telles que le nom d'utilisateur actuel et le texte de la barre de titre. J'expose également d'autres modules de classe depuis clsApp , comme clsStatus et clsRegistry , qui offrent un accès plus lisible à la barre d'état Access et au registre Windows, respectivement.

Cependant, je n'ai pas besoin d'accéder à la barre d'état ou au registre Windows dans chaque projet. Donc, pour éviter de créer une dépendance sur le clsStatus ou clsRegistry classes, je commenterais le code faisant référence à ces classes à l'aide d'un "jeton de commentaire" unique.

C'est plus facile à démontrer avec un exemple :

' Notes     
' - Find and replace '$$ with blank to enable Status property (requires clsStatus)
' - Find and replace '&& with blank to enable Reg property (requires clsRegistry)

'$$Private m_objStatus As clsStatus
'&&Private m_objReg As clsRegistry

'$$Public Property Get Status() As clsStatus
'$$    Set Status = m_objStatus
'$$End Property

'&&Public Property Get Reg() As clsRegistry
'&&    Set Reg = m_objReg
'&&End Property

Private Sub Class_Initialize()
    '$$    Set m_objStatus = New clsStatus
    '&&    Set m_objReg = New clsRegistry
End Sub

Si je voulais activer le Status propriété de la classe ci-dessus, je pourrais effectuer une recherche et un remplacement globaux sur '$$ .

Cela a bien fonctionné pendant un certain temps, mais cela m'a toujours semblé maladroit. Probablement parce que c'était le cas. L'autre chose à noter est que les jetons de commentaire devraient être globalement uniques dans toute ma bibliothèque de codes. Cela aurait été un cauchemar de maintenance si j'avais suivi cette approche pendant longtemps.

Utiliser la compilation conditionnelle

Une approche beaucoup plus propre consiste à tirer parti de la compilation conditionnelle. Ce sont les lignes dans VBA qui commencent par un signe dièse/hashtag ("#"). Les lignes commençant par ce caractère sont soumises à un "prétraitement".

Qu'est-ce que le prétraitement ? C'est une étape que les langages de programmation franchissent avant la compilation. Ainsi, avant toute vérification du temps de compilation, les lignes de prétraitement sont évaluées. Cela nous permet de placer du code qui, autrement, ne parviendrait pas à se compiler dans nos projets.

Comment pouvons-nous en tirer parti avec nos bibliothèques de code ? Encore une fois, c'est plus simple à démontrer avec un exemple :

' Notes 
' - Replace the '$$ and '&& kludges with conditional compilation

#Const EnableStatusProperty = True  'If True, requires import of clsStatus class
#Const EnableRegProperty = False  'If True, requires import of clsRegistry class

#If EnableStatusProperty Then
Private m_objStatus As clsStatus
#End If
#If EnableRegProperty Then
Private m_objReg As clsRegistry
#End If

#If EnableStatusProperty Then
Public Property Get Status() As clsStatus
    Set Status = m_objStatus
End Property
#End If

#If EnableRegProperty Then
Public Property Get Reg() As clsRegistry
    Set Reg = m_objReg
End Property
#End If

Private Sub Class_Initialize()
#If EnableStatusProperty Then
    Set m_objStatus = New clsStatus
#End If
#If EnableRegProperty Then
    Set m_objReg = New clsRegistry
#End If
End Sub

Le meilleur des deux mondes

Comme vous pouvez le voir, c'est un moyen très propre d'éviter le problème du "train de dépendance".

Cela nous permet de créer des dépendances facultatives . Chaque morceau de code qui s'appuie sur un autre module de bibliothèque de code est enveloppé dans une instruction de compilation conditionnelle #If ... Then. La ou les constantes de compilation conditionnelle sont toutes répertoriées en haut du module de code.

Maintenant, lorsque nous réimportons une version mise à jour de notre module de bibliothèque de code, nous devons simplement passer en revue et définir les indicateurs de compilation conditionnelle sur ce qui existait auparavant. Si nous ne nous rappelons pas comment les drapeaux ont été définis, nous devrions pouvoir continuer à compiler et à ajuster les drapeaux jusqu'à ce que le projet soit complètement compilé.

Et si nous utilisons le contrôle de version, nous n'avons pas à nous soucier d'oublier ce qui existait auparavant.