Ο σχεδιασμός βάσει τομέα (εν συντομία η DDD) δεν είναι τεχνολογία ή μεθοδολογία. Το DDD παρέχει μια δομή πρακτικών και ορολογίας για τη λήψη αποφάσεων σχεδιασμού που εστιάζουν και επιταχύνουν έργα λογισμικού που ασχολούνται με περίπλοκους τομείς. Οπως και περιγράφεται από τον Eric Evans και Martin Fowler, τα αντικείμενα τομέα είναι ένα μέρος για να τεθούν κανόνες επικύρωσης και επιχειρηματική λογική.
Έρικ Έβανς:
Επίπεδο τομέα (ή Επίπεδο μοντέλου): Υπεύθυνος για την εκπροσώπηση εννοιών της επιχείρησης, πληροφορίες σχετικά με την κατάσταση της επιχείρησης και επιχειρηματικούς κανόνες. Η κατάσταση που αντικατοπτρίζει την κατάσταση της επιχείρησης ελέγχεται και χρησιμοποιείται εδώ, παρόλο που οι τεχνικές λεπτομέρειες της αποθήκευσής της ανατίθενται στην υποδομή. Αυτό το επίπεδο είναι η καρδιά του επιχειρηματικού λογισμικού.
Martin Fowler:
Η λογική που πρέπει να υπάρχει σε ένα αντικείμενο τομέα είναι η λογική τομέα - επικυρώσεις, υπολογισμοί, επιχειρηματικοί κανόνες - ό, τι θέλετε να το ονομάσετε.
Η τοποθέτηση όλης της επικύρωσης σε αντικείμενα τομέα έχει ως αποτέλεσμα τεράστια και πολύπλοκα αντικείμενα τομέα για εργασία. Προσωπικά, προτιμώ πολύ την ιδέα της αποσύνδεσης επικυρώσεων τομέα σε ξεχωριστά στοιχεία επικυρωτή που μπορούν να επαναχρησιμοποιηθούν ανά πάσα στιγμή και που θα βασίζονται στο περιβάλλον και τη δράση του χρήστη.
Όπως έγραψε ο Martin Fowler σε ένα υπέροχο άρθρο: Επικύρωση με βάση τα συμφραζόμενα .
Ένα κοινό πράγμα που βλέπω ότι κάνουν οι άνθρωποι είναι να αναπτύξουν ρουτίνες επικύρωσης για αντικείμενα. Αυτές οι ρουτίνες έρχονται με διάφορους τρόπους, μπορεί να είναι στο αντικείμενο ή στο εξωτερικό, μπορεί να επιστρέψουν ένα boolean ή να ρίξουν μια εξαίρεση για να δείξουν αστοχία. Ένα πράγμα που νομίζω ότι ταξιδεύει συνεχώς στους ανθρώπους είναι όταν σκέφτονται την εγκυρότητα αντικειμένου με τρόπο ανεξάρτητο από το περιβάλλον, όπως υποδηλώνει μια μέθοδος isValid. […] Νομίζω ότι είναι πολύ πιο χρήσιμο να θεωρούμε την επικύρωση ως κάτι που συνδέεται με ένα πλαίσιο, συνήθως μια ενέργεια που θέλετε να κάνετε. Όπως να ρωτήσω εάν αυτή η παραγγελία ισχύει για συμπλήρωση ή είναι έγκυρος αυτός ο πελάτης για να κάνει check in στο ξενοδοχείο. Έτσι, αντί να έχετε μεθόδους όπως το isValid, έχετε μεθόδους όπως το isValidForCheckIn.
Σε αυτό το άρθρο θα εφαρμόσουμε μια απλή διεπαφή ItemValidator για την οποία πρέπει να εφαρμόσετε ένα επικυρώνω μέθοδος με τύπο επιστροφής Αποτέλεσμα επικύρωσης . Το ValidationResult είναι ένα αντικείμενο που περιέχει το αντικείμενο που έχει επικυρωθεί και επίσης το Μηνύματα αντικείμενο. Το τελευταίο περιέχει μια συσσώρευση σφαλμάτων, προειδοποιήσεων και καταστάσεων επικύρωσης πληροφοριών (μηνύματα) που εξαρτώνται από το πλαίσιο εκτέλεσης.
Οι επικυρωτές είναι αποσυνδεδεμένα συστατικά που μπορούν εύκολα να επαναχρησιμοποιηθούν οπουδήποτε χρειάζονται. Με αυτήν την προσέγγιση, όλες οι εξαρτήσεις, οι οποίες απαιτούνται για ελέγχους επικύρωσης, μπορούν να εγχυθούν εύκολα. Για παράδειγμα, για να ελέγξετε τη βάση δεδομένων εάν υπάρχει χρήστης με δεδομένο email χρησιμοποιείται μόνο το UserDomainService.
Η αποσύνδεση των επικυρωτών θα γίνεται ανά πλαίσιο (ενέργεια). Επομένως, εάν η ενέργεια UserCreate και η ενέργεια UserUpdate θα έχουν αποσυνδεδεμένα στοιχεία ή οποιαδήποτε άλλη ενέργεια (UserActivate, UserDelete, AdCampaignLaunch κ.λπ.), η επικύρωση μπορεί αναπτύσσεται γρήγορα .
Κάθε επικυρωτής ενέργειας πρέπει να έχει ένα αντίστοιχο μοντέλο δράσης που θα έχει μόνο τα επιτρεπόμενα πεδία δράσης. Για τη δημιουργία χρηστών, απαιτούνται τα ακόλουθα πεδία:
UserCreateModel:
{ 'firstName': 'John', 'lastName': 'Doe', 'email': ' [email protected] ', 'password': 'MTIzNDU=' }
Και για την ενημέρωση του χρήστη επιτρέπονται τα ακόλουθα εξωτερικόId , όνομα και επίθετο . εξωτερικόId χρησιμοποιείται για την αναγνώριση του χρήστη και την αλλαγή μόνο του όνομα και επίθετο επιτρέπεται.
UserUpdateModel:
{ 'externalId': 'a55ccd60-9d82-11e5-9f52-0002a5d5c51b', 'firstName': 'John Updated', 'lastName': 'Doe Updated' }
Οι επικυρώσεις ακεραιότητας πεδίου μπορούν να κοινοποιηθούν, το μέγιστο μήκος ονόματος πρώτου ονόματος είναι πάντα 255 χαρακτήρες.
Κατά την επικύρωση, είναι επιθυμητό να μην λαμβάνετε μόνο το πρώτο σφάλμα που παρουσιάζεται, αλλά και μια λίστα με όλα τα προβλήματα που αντιμετωπίστηκαν. Για παράδειγμα, τα ακόλουθα 3 ζητήματα ενδέχεται να προκύψουν ταυτόχρονα και μπορούν να αναφερθούν ανάλογα κατά την εκτέλεση:
Για να επιτευχθεί αυτό το είδος επικύρωσης, απαιτείται κάτι σαν εργαλείο δημιουργίας κατάστασης επικύρωσης και για το σκοπό αυτό Μηνύματα εισάγεται. Μηνύματα είναι μια ιδέα που άκουσα από τον σπουδαίο μέντορά μου πριν από χρόνια όταν την παρουσίασε για να υποστηρίξει την επικύρωση και επίσης για διάφορα άλλα πράγματα που μπορούν να γίνουν με αυτήν, καθώς τα Μηνύματα δεν είναι μόνο για επικύρωση.
Σημειώστε ότι στις παρακάτω ενότητες θα χρησιμοποιήσουμε το Scala για να απεικονίσουμε την εφαρμογή. Σε περίπτωση που δεν είστε Ειδικός της Scala , μην φοβάστε γιατί θα πρέπει να ακολουθείτε εύκολα.
Μηνύματα είναι ένα αντικείμενο που αντιπροσωπεύει το εργαλείο δημιουργίας επικύρωσης. Παρέχει έναν εύκολο τρόπο συλλογής σφαλμάτων, προειδοποιήσεων και μηνυμάτων πληροφοριών κατά την επικύρωση. Καθε Μηνύματα το αντικείμενο έχει μια εσωτερική συλλογή Μήνυμα αντικείμενα και μπορεί επίσης να έχει αναφορά σε γονικά μηνύματα αντικείμενο.
Ένα αντικείμενο μηνύματος είναι ένα αντικείμενο που μπορεί να έχει τύπος , κείμενο μηνύματος , κλειδί (το οποίο είναι προαιρετικό και χρησιμοποιείται για την υποστήριξη της επικύρωσης συγκεκριμένων εισόδων που προσδιορίζονται από το αναγνωριστικό), και τέλος παιδικά μηνύματα που αποδεικνύει έναν εξαιρετικό τρόπο για τη δημιουργία σύνθετων δέντρων μηνυμάτων.
Ένα μήνυμα μπορεί να είναι ένας από τους ακόλουθους τύπους:
Τα μηνύματα που έχουν δομηθεί έτσι, μας επιτρέπουν να τα δημιουργούμε επαναληπτικά και επιτρέπει επίσης τη λήψη αποφάσεων σχετικά με τις επόμενες ενέργειες με βάση την κατάσταση προηγούμενων μηνυμάτων. Για παράδειγμα, εκτέλεση επικύρωσης κατά τη δημιουργία του χρήστη:
@Component class UserCreateValidator @Autowired (private val entityDomainService: UserDomainService) extends ItemValidator[UserCreateEntity] { Asserts.argumentIsNotNull(entityDomainService) private val MAX_ALLOWED_LENGTH = 80 private val MAX_ALLOWED_CHARACTER_ERROR = s'must be less than or equal to $MAX_ALLOWED_LENGTH character' override def validate(item: UserCreateEntity): ValidationResult[UserCreateEntity] = { Asserts.argumentIsNotNull(item) val validationMessages = Messages.of validateFirstName (item, validationMessages) validateLastName (item, validationMessages) validateEmail (item, validationMessages) validateUserName (item, validationMessages) validatePassword (item, validationMessages) ValidationResult( validatedItem = item, messages = validationMessages ) } private def validateFirstName(item: UserCreateEntity, validationMessages: Messages) { val localMessages = Messages.of(validationMessages) val fieldValue = item.firstName ValidateUtils.validateLengthIsLessThanOrEqual( fieldValue, MAX_ALLOWED_LENGTH, localMessages, UserCreateEntity.FIRST_NAME_FORM_ID.value, MAX_ALLOWED_CHARACTER_ERROR ) } private def validateLastName(item: UserCreateEntity, validationMessages: Messages) { val localMessages = Messages.of(validationMessages) val fieldValue = item.lastName ValidateUtils.validateLengthIsLessThanOrEqual( fieldValue, MAX_ALLOWED_LENGTH, localMessages, UserCreateEntity.LAST_NAME_FORM_ID.value, MAX_ALLOWED_CHARACTER_ERROR ) } private def validateEmail(item: UserCreateEntity, validationMessages: Messages) { val localMessages = Messages.of(validationMessages) val fieldValue = item.email ValidateUtils.validateEmail( fieldValue, UserCreateEntity.EMAIL_FORM_ID, localMessages ) ValidateUtils.validateLengthIsLessThanOrEqual( fieldValue, MAX_ALLOWED_LENGTH, localMessages, UserCreateEntity.EMAIL_FORM_ID.value, MAX_ALLOWED_CHARACTER_ERROR ) if(!localMessages.hasErrors()) { val doesExistWithEmail = this.entityDomainService.doesExistByByEmail(fieldValue) ValidateUtils.isFalse( doesExistWithEmail, localMessages, UserCreateEntity.EMAIL_FORM_ID.value, 'User already exists with this email' ) } } private def validateUserName(item: UserCreateEntity, validationMessages: Messages) { val localMessages = Messages.of(validationMessages) val fieldValue = item.username ValidateUtils.validateLengthIsLessThanOrEqual( fieldValue, MAX_ALLOWED_LENGTH, localMessages, UserCreateEntity.USERNAME_FORM_ID.value, MAX_ALLOWED_CHARACTER_ERROR ) if(!localMessages.hasErrors()) { val doesExistWithUsername = this.entityDomainService.doesExistByUsername(fieldValue) ValidateUtils.isFalse( doesExistWithUsername, localMessages, UserCreateEntity.USERNAME_FORM_ID.value, 'User already exists with this username' ) } } private def validatePassword(item: UserCreateEntity, validationMessages: Messages) { val localMessages = Messages.of(validationMessages) val fieldValue = item.password ValidateUtils.validateLengthIsLessThanOrEqual( fieldValue, MAX_ALLOWED_LENGTH, localMessages, UserCreateEntity.PASSWORD_FORM_ID.value, MAX_ALLOWED_CHARACTER_ERROR ) } }
Εξετάζοντας αυτόν τον κωδικό, μπορείτε να δείτε τη χρήση του ValidateUtils. Αυτές οι βοηθητικές λειτουργίες χρησιμοποιούνται για τη συμπλήρωση του αντικειμένου Μηνύματα σε προκαθορισμένες περιπτώσεις. Μπορείτε να ελέγξετε την εφαρμογή του ΕπικύρωσηUtils στο Github κώδικας.
Κατά τη διάρκεια της επικύρωσης email, πρώτα ελέγχεται εάν το email είναι έγκυρο μέσω κλήσης ValidateUtils.validateEmail (… και ελέγχεται επίσης εάν το email έχει έγκυρη διάρκεια κλήσης ΕπικύρωσηUtils.validateLengthIsLessThanOrEqual (… . Μόλις ολοκληρωθούν αυτές οι δύο επικυρώσεις, ελέγχεται εάν το email έχει ήδη εκχωρηθεί σε κάποιον Χρήστη, μόνο εάν οι προηγούμενες συνθήκες επικύρωσης email περνούν και αυτό γίνεται με εάν (! localMessages.hasErrors ()) {… . Με αυτόν τον τρόπο μπορούν να αποφευχθούν ακριβές κλήσεις βάσης δεδομένων. Αυτό είναι μόνο μέρος του UserCreateValidator. Μπορείτε να βρείτε τον πλήρη πηγαίο κώδικα εδώ .
Παρατηρήστε ότι μία από τις παραμέτρους επικύρωσης ξεχωρίζει: UserCreateEntity.EMAIL_FORM_ID . Αυτή η παράμετρος συνδέει την κατάσταση επικύρωσης με ένα συγκεκριμένο αναγνωριστικό εισόδου.
Σε προηγούμενα παραδείγματα, η επόμενη δράση αποφασίζεται με βάση το γεγονός εάν Μηνύματα το αντικείμενο έχει σφάλματα (χρησιμοποιώντας τη μέθοδο hasErrors). Κάποιος μπορεί εύκολα να ελέγξει αν υπάρχουν μηνύματα 'ΠΡΟΕΙΔΟΠΟΙΗΣΗ' και να προσπαθήσει ξανά εάν είναι απαραίτητο.
Ένα πράγμα που μπορεί να παρατηρηθεί είναι ο τρόπος τοπικά μηνύματα χρησιμοποιείται. Τα τοπικά μηνύματα είναι μηνύματα που έχουν δημιουργηθεί το ίδιο με οποιοδήποτε μήνυμα, αλλά με τα γονικά μηνύματα. Με αυτό, ο στόχος είναι να υπάρχει αναφορά μόνο στην τρέχουσα κατάσταση επικύρωσης (σε αυτό το παράδειγμα emailValidation), έτσι localMessages.hasErrors μπορεί να κληθεί, όπου ελέγχεται μόνο εάν το περιβάλλον επικύρωσης email hasErrors. Επίσης, όταν προστίθεται ένα μήνυμα στο localMessages, προστίθεται επίσης στο parentMessages και έτσι όλα τα μηνύματα επικύρωσης υπάρχουν σε υψηλότερο περιβάλλον του UserCreateValidation.
Τώρα που έχουμε δει τα Μηνύματα σε δράση, στο επόμενο κεφάλαιο θα επικεντρωθούμε στο ItemValidator.
Το ItemValidator είναι ένα απλό χαρακτηριστικό (διεπαφή) που αναγκάζει τους προγραμματιστές να εφαρμόσουν τη μέθοδο επικυρώνω , το οποίο πρέπει να επιστρέψει το ValidationResult.
Item Validator:
trait ItemValidator[T] { def validate(item:T) : ValidationResult[T] }
Αποτέλεσμα επικύρωσης:
case class ValidationResult[T: Writes]( validatedItem : T, messages : Messages ) { Asserts.argumentIsNotNull(validatedItem) Asserts.argumentIsNotNull(messages) def isValid :Boolean = { !messages.hasErrors } def errorsRestResponse = { Asserts.argumentIsTrue(!this.isValid) ResponseTools.of( data = Some(this.validatedItem), messages = Some(messages) ) } }
Όταν ItemValidators όπως UserCreateValidator εφαρμόζονται για να είναι ένεση εξάρτησης στοιχεία, τότε αντικείμενα ItemValidator μπορούν να εγχυθούν και να επαναχρησιμοποιηθούν σε οποιοδήποτε αντικείμενο που χρειάζεται επικύρωση ενέργειας UserCreate.
Μετά την εκτέλεση της επικύρωσης, ελέγχεται εάν η επικύρωση ήταν επιτυχής. Εάν είναι, τότε τα δεδομένα χρήστη διατηρούνται στη βάση δεδομένων, αλλά αν όχι επιστρέφεται η απόκριση API που περιέχει σφάλματα επικύρωσης.
Στην επόμενη ενότητα θα δούμε πώς μπορούμε να παρουσιάσουμε σφάλματα επικύρωσης στην απόκριση RESTful API και επίσης πώς να επικοινωνούμε με τους καταναλωτές API σχετικά με τις καταστάσεις δράσης εκτέλεσης.
Αφού επικυρωθεί με επιτυχία η ενέργεια του χρήστη, στην περίπτωση που δημιουργήθηκε ο χρήστης, τα αποτελέσματα ενεργειών επικύρωσης πρέπει να εμφανίζονται στον RESTful API καταναλωτή. Ο καλύτερος τρόπος είναι να έχετε μια ενοποιημένη απόκριση API όπου θα αλλάζει μόνο το περιβάλλον (από άποψη JSON, τιμή 'δεδομένων'). Με ενοποιημένες απαντήσεις, τα σφάλματα μπορούν να παρουσιαστούν εύκολα στους καταναλωτές RESTful API.
Ενοποιημένη δομή απόκρισης:
{ 'messages' : { 'global' : { 'info': [], 'warnings': [], 'errors': [] }, 'local' : [] }, 'data':{} }
Η ενοποιημένη απόκριση είναι δομημένη ώστε να έχει δύο επίπεδα μηνυμάτων, παγκόσμια και τοπικά. Τα τοπικά μηνύματα είναι μηνύματα που συνδέονται με συγκεκριμένες εισόδους. Όπως 'το όνομα χρήστη είναι πολύ μεγάλο, επιτρέπονται το πολύ 80 χαρακτήρες' _. Τα καθολικά μηνύματα είναι μηνύματα που αντικατοπτρίζουν την κατάσταση ολόκληρων δεδομένων στη σελίδα, όπως 'ο χρήστης δεν θα είναι ενεργός έως ότου εγκριθεί'. Τα τοπικά και παγκόσμια μηνύματα έχουν τρία επίπεδα - λάθος, προειδοποίηση και πληροφορίες. Η τιμή των «δεδομένων» είναι συγκεκριμένη για το περιβάλλον. Κατά τη δημιουργία χρηστών το πεδίο δεδομένων θα περιέχει δεδομένα χρηστών, αλλά κατά τη λήψη μιας λίστας χρηστών το πεδίο δεδομένων θα είναι μια σειρά χρηστών.
Με αυτό το είδος δομημένης απόκρισης, ο χειριστής διεπαφής χρήστη μπορεί να δημιουργηθεί εύκολα, ο οποίος θα είναι υπεύθυνος για την εμφάνιση σφαλμάτων, προειδοποιήσεων και ενημερωτικών μηνυμάτων. Τα καθολικά μηνύματα θα εμφανίζονται στο πάνω μέρος της σελίδας, επειδή σχετίζονται με την καθολική κατάσταση δράσης API και τα τοπικά μηνύματα μπορούν να εμφανίζονται κοντά στην καθορισμένη είσοδο (πεδίο), καθώς σχετίζονται άμεσα με την τιμή του πεδίου. Τα μηνύματα σφάλματος μπορούν να παρουσιαστούν με κόκκινο χρώμα, προειδοποιητικά μηνύματα με κίτρινο χρώμα και πληροφορίες με μπλε χρώμα.
Για παράδειγμα, σε μια εφαρμογή πελάτη που βασίζεται σε AngularJS μπορούμε να έχουμε δύο οδηγίες υπεύθυνες για τον χειρισμό τοπικών και παγκόσμιων μηνυμάτων απόκρισης, έτσι ώστε μόνο αυτοί οι δύο χειριστές να μπορούν να αντιμετωπίζουν όλες τις απαντήσεις με συνεπή τρόπο.
Η οδηγία για το τοπικό μήνυμα θα πρέπει να εφαρμοστεί σε ένα στοιχείο γονέα στο πραγματικό στοιχείο που κρατά όλα τα μηνύματα.
localmessages.direcitive.js :
(function() { 'use strict'; angular .module('reactiveClient') .directive('localMessagesValidationDirective', localMessagesValidationDirective); /** @ngInject */ function localMessagesValidationDirective(_) { return { restrict: 'AE', transclude: true, scope: { binder: '=' }, template: ' ', link: function (scope, element) { var messagesWatchCleanUp = scope.$watch('binder', messagesBinderWatchCallback); scope.$on('$destroy', function() { messagesWatchCleanUp(); }); function messagesBinderWatchCallback (messagesResponse) { if (messagesResponse != undefined && messagesResponse.messages != undefined) { if (messagesResponse.messages.local.length > 0) { element.find('.alert').remove(); _.forEach(messagesResponse.messages.local, function (localMsg) { var selector = element.find('[id='' + localMsg.inputId + '']').parent(); _.forEach(localMsg.info, function (msg) { var infoMsg = ' ×' + msg + ' '; selector.after(infoMsg); }); _.forEach(localMsg.warnings, function (msg) { var warningMsg = ' ×' + msg + ' '; selector.after(warningMsg); }); _.forEach(localMsg.errors, function (msg) { var errorMsg = ' ×' + msg + ' '; selector.after(errorMsg); }); }); } } } } } } })();
Η οδηγία για καθολικά μηνύματα θα συμπεριληφθεί στο έγγραφο ριζικής διάταξης (index.html) και θα εγγραφεί σε ένα συμβάν για το χειρισμό όλων των καθολικών μηνυμάτων.
globalmessages.directive.js :
(function() { 'use strict'; angular .module('reactiveClient') .directive('globalMessagesValidationDirective', globalMessagesValidationDirective); /** @ngInject */ function globalMessagesValidationDirective(_, toastr, $rootScope, $log) { return { restrict: 'AE', link: function (scope) { var cleanUpListener = $rootScope.$on('globalMessages', globalMessagesWatchCallback); scope.$on('$destroy', function() { cleanUpListener(); }); function globalMessagesWatchCallback (event, messagesResponse) { $log.log('received rootScope event: ' + event); if (messagesResponse != undefined && messagesResponse.messages != undefined) { if (messagesResponse.messages.global != undefined) { _.forEach(messagesResponse.messages.global.info, function (msg) { toastr.info(msg); }); _.forEach(messagesResponse.messages.global.warnings, function (msg) { toastr.warning(msg); }); _.forEach(messagesResponse.messages.global.errors, function (msg) { toastr.error(msg); }); } } } } } } })();
Για ένα πιο πλήρες παράδειγμα, ας εξετάσουμε την ακόλουθη απάντηση που περιέχει ένα τοπικό μήνυμα:
{ 'messages' : { 'global' : { 'info': [], 'warnings': [], 'errors': [] }, 'local' : [ { 'inputId' : 'email', 'errors' : ['User already exists with this email'], 'warnings' : [], 'info' : [] } ] }, 'data':{ 'firstName': 'John', 'lastName': 'Doe', 'email': ' [email protected] ', 'password': 'MTIzNDU=' } }
Η παραπάνω απάντηση μπορεί να οδηγήσει σε κάτι ως εξής:
Από την άλλη πλευρά, με ένα παγκόσμιο μήνυμα ως απάντηση:
{ 'messages' : { 'global' : { 'info': ['User successfully created.'], 'warnings': ['User will not be available for login until is activated'], 'errors': [] }, 'local' : [] }, 'data':{ 'externalId': 'a55ccd60-9d82-11e5-9f52-0002a5d5c51b', 'firstName': 'John', 'lastName': 'Doe', 'email': ' [email protected] ' } }
Η εφαρμογή πελάτη μπορεί πλέον να εμφανίζει το μήνυμα με μεγαλύτερη προβολή:
Στα παραπάνω παραδείγματα μπορεί να φανεί πώς μπορεί να αντιμετωπιστεί μια ενοποιημένη δομή απόκρισης για οποιοδήποτε αίτημα με τον ίδιο χειριστή.
Η εφαρμογή επικύρωσης σε μεγάλα έργα μπορεί να προκαλέσει σύγχυση και κανόνες επικύρωσης μπορούν να βρεθούν παντού σε ολόκληρο τον κώδικα του έργου. Η διατήρηση της επικύρωσης συνεπή και καλά δομημένη καθιστά τα πράγματα ευκολότερα και επαναχρησιμοποιήσιμα.
Μπορείτε να βρείτε αυτές τις ιδέες που εφαρμόζονται σε δύο διαφορετικές εκδόσεις των πλακών boiler παρακάτω:
Σε αυτό το άρθρο έχω παρουσιάσει τις προτάσεις μου σχετικά με τον τρόπο υποστήριξης βαθιάς, σύνθετης επικύρωσης περιβάλλοντος που μπορεί εύκολα να παρουσιαστεί σε έναν χρήστη. Ελπίζω ότι αυτό θα σας βοηθήσει να λύσετε τις προκλήσεις της σωστής επικύρωσης και του χειρισμού σφαλμάτων μια για πάντα. Μη διστάσετε να αφήσετε τα σχόλιά σας και να μοιραστείτε τις σκέψεις σας παρακάτω.