Determinations et Validations sont les deux mecanismes dans RAP pour executer automatiquement la logique metier. Les Determinations definissent des valeurs, les Validations les verifient. La bonne comprehension du timing (quand quoi est execute) est cruciale pour des RAP Business Objects sans erreur.
La difference en un coup d’oeil
┌─────────────────────────────────────────────────────────────┐│ Action utilisateur (Create/Update) │└────────────────────┬────────────────────────────────────────┘ │ ▼ ┌───────────────────────┐ │ DETERMINATION │ ← Definit automatiquement les valeurs │ "Qu'est-ce qui │ (Status, Numeros, Valeurs par defaut) │ manque ?" │ └───────────┬───────────┘ │ ▼ ┌───────────────────────┐ │ VALIDATION │ ← Verifie les regles metier │ "Est-ce correct ?" │ (Logique de dates, Champs obligatoires) └───────────┬───────────┘ │ ▼ (seulement en cas de succes) ┌───────────────────────┐ │ Save to Database │ └───────────────────────┘| Aspect | Determination | Validation |
|---|---|---|
| Objectif | Definir/calculer des valeurs | Verifier des valeurs |
| Timing | on modify ou on save | on save |
| Modifications | ✅ Peut modifier l’entite | ❌ Lecture seule, pas de modifications |
| Erreurs | Pas d’erreurs directes | Remplit FAILED & REPORTED |
| Exemple | Definir le status a ‘O’ | Verifier que la date de fin est apres le debut |
| Ordre | D’abord (avant Validation) | Ensuite (apres Determination) |
Determinations : Definition automatique des valeurs
Quand utiliser les Determinations ?
✅ Parfait pour :
- Definir les valeurs par defaut (Status = ‘Open’)
- Calculer des champs (Prix total = Prix × Quantite)
- Mettre a jour les champs dependants
- Definir les timestamps (CreatedAt, LastChangedAt)
- Valeurs basees sur la logique metier (Remise selon la categorie client)
Syntaxe dans la Behavior Definition
define behavior for ZI_Travel alias Travel{ // Syntaxe Determination : determination <MethodName> on <Trigger> { <TriggerCondition>; }
// Trigger : modify (immediat) ou save (avant DB-Commit) // TriggerCondition : create, update, field <FieldName>}Exemple 1 : Definir le status lors de la creation
// Behavior Definitiondefine behavior for ZI_Travel alias Travelpersistent table ztravel{ create; update;
field ( readonly ) TravelId, Status; field ( readonly ) CreatedBy, CreatedAt;
// Determination : Lors de Create → Definir le Status a 'O' (Open) determination setInitialStatus on modify { create; }}// Behavior ImplementationCLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS setInitialStatus FOR DETERMINE ON MODIFY IMPORTING keys FOR Travel~setInitialStatus.ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD setInitialStatus. " 1. Lire les donnees actuelles READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
" 2. Mettre a jour uniquement les entites sans Status MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( Status CreatedBy CreatedAt ) WITH VALUE #( FOR travel IN lt_travel WHERE ( Status IS INITIAL ) ( %tky = travel-%tky Status = 'O' " Open CreatedBy = cl_abap_context_info=>get_user_name( ) CreatedAt = cl_abap_context_info=>get_system_date( ) ) ) REPORTED DATA(update_reported). ENDMETHOD.
ENDCLASS.Deroulement :
Utilisateur : CREATE Travel avec Description = 'Voyage d affaires" ↓Framework : Create en memoire ↓Determination : setInitialStatus → Status = 'O" → CreatedBy = sy-uname → CreatedAt = today ↓(Les validations sont executees) ↓Framework : INSERT INTO ztravelExemple 2 : Calculer le prix total (on modify)
// Behavior Definitiondefine behavior for ZI_Travel alias Travel{ // Lors d'un changement de BeginDate ou EndDate → Recalculer le prix determination calculateTotalPrice on modify { field BeginDate, EndDate; }}METHOD calculateTotalPrice. " Lire les donnees READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( TravelId BeginDate EndDate ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel). " Calculer le nombre de jours DATA(lv_days) = ls_travel-EndDate - ls_travel-BeginDate + 1.
" Prix de base par jour (ex. depuis le customizing) DATA(lv_price_per_day) = 100. " EUR
" Prix total DATA(lv_total) = lv_days * lv_price_per_day.
" Remise pour voyages longs IF lv_days > 7. lv_total = lv_total * '0.90'. " 10% de remise ENDIF.
" Definir la valeur MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( TotalPrice ) WITH VALUE #( ( %tky = ls_travel-%tky TotalPrice = lv_total ) ). ENDLOOP.ENDMETHOD.Exemples de triggers :
" Executer lors de CREATEdetermination setDefaults on modify { create; }
" Executer lors de UPDATEdetermination recalculate on modify { update; }
" Lors de CREATE et UPDATEdetermination calculate on modify { create; update; }
" Seulement lorsque certains champs sont modifiesdetermination updateDependentFields on modify { field Price, Quantity, Discount;}
" Lors de SAVE (juste avant le DB-Commit)determination finalizeData on save { create; update; }Exemple 3 : Definir les champs dependants (on save)
// Behavior Definitiondefine behavior for ZI_Travel alias Travel{ // Juste avant le Save : Definir les champs d'approbation determination setApprovalData on save { update; }}METHOD setApprovalData. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( Status ApprovedBy ApprovedAt ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( ApprovedBy ApprovedAt ) WITH VALUE #( FOR travel IN lt_travel WHERE ( Status = 'A' AND ApprovedBy IS INITIAL ) ( %tky = travel-%tky ApprovedBy = cl_abap_context_info=>get_user_name( ) ApprovedAt = cl_abap_context_info=>get_system_date( ) ) ) REPORTED DATA(update_reported).ENDMETHOD.Validations : Verifier les regles metier
Quand utiliser les Validations ?
✅ Parfait pour :
- Verifier les champs obligatoires
- Logique de dates (Date de fin apres le debut)
- Verification des plages de valeurs (Remise ≤ 100%)
- Verifier les cles etrangeres (Le client existe-t-il ?)
- Regles metier complexes
❌ PAS pour :
- Definir des valeurs (→ Determination!)
- Calculs (→ Determination!)
- Juste enregistrer des warnings (→ OK, mais pas comme erreur)
Syntaxe dans la Behavior Definition
define behavior for ZI_Travel alias Travel{ // Syntaxe Validation : validation <MethodName> on save { <TriggerCondition>; }
// Trigger : TOUJOURS "on save" (juste avant le DB-Commit) // TriggerCondition : create, update, field <FieldName>}Exemple 1 : Verifier la logique des dates
// Behavior Definitiondefine behavior for ZI_Travel alias Travel{ create; update;
// Validation : Lors du Save → Verifier la date validation validateDates on save { field BeginDate, EndDate; }}// Behavior ImplementationCLASS lhc_travel IMPLEMENTATION.
METHOD validateDates. " 1. Lire les donnees READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( TravelId BeginDate EndDate ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
" 2. Verifier chaque entite LOOP AT lt_travel INTO DATA(ls_travel).
" Regle 1 : EndDate doit etre apres BeginDate IF ls_travel-EndDate < ls_travel-BeginDate.
" Remplir FAILED (erreur technique) APPEND VALUE #( %tky = ls_travel-%tky %element-EndDate = if_abap_behv=>mk-on ) TO failed-travel.
" Remplir REPORTED (message d'erreur pour UI) APPEND VALUE #( %tky = ls_travel-%tky %element-EndDate = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |La date de fin ({ ls_travel-EndDate DATE = USER }) | && |doit etre apres la date de debut ({ ls_travel-BeginDate DATE = USER })| ) ) TO reported-travel. ENDIF.
" Regle 2 : BeginDate ne doit pas etre dans le passe IF ls_travel-BeginDate < cl_abap_context_info=>get_system_date( ).
APPEND VALUE #( %tky = ls_travel-%tky %element-BeginDate = if_abap_behv=>mk-on ) TO failed-travel.
APPEND VALUE #( %tky = ls_travel-%tky %element-BeginDate = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Le debut du voyage ne peut pas etre dans le passe" ) ) TO reported-travel. ENDIF.
ENDLOOP. ENDMETHOD.
ENDCLASS.Que se passe-t-il en cas d’erreur ?
Utilisateur : UPDATE Travel, EndDate = '20250101', BeginDate = '20250115" ↓(Les determinations sont executees) ↓Validation : validateDates → Verification : EndDate < BeginDate? → OUI! → FAILED-travel rempli → REPORTED-travel rempli ↓Framework : ROLLBACK (pas d'INSERT/UPDATE) ↓UI : Afficher le message d'erreurExemple 2 : Verifier les cles etrangeres
// Behavior Definitiondefine behavior for ZI_Travel alias Travel{ validation validateCustomer on save { field CustomerId; }}METHOD validateCustomer. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( CustomerId ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
" Collecter tous les CustomerIds DATA(lt_customer_ids) = VALUE string_table( FOR travel IN lt_travel ( travel-CustomerId ) ).
" Verifier si les clients existent (via Released API) SELECT Customer FROM I_Customer FOR ALL ENTRIES IN @lt_customer_ids WHERE Customer = @lt_customer_ids-table_line INTO TABLE @DATA(lt_valid_customers).
" Erreur pour les clients inexistants LOOP AT lt_travel INTO DATA(ls_travel). IF NOT line_exists( lt_valid_customers[ table_line = ls_travel-CustomerId ] ).
APPEND VALUE #( %tky = ls_travel-%tky %element-CustomerId = if_abap_behv=>mk-on ) TO failed-travel.
APPEND VALUE #( %tky = ls_travel-%tky %element-CustomerId = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Le client { ls_travel-CustomerId } n'existe pas| ) ) TO reported-travel.
ENDIF. ENDLOOP.ENDMETHOD.Exemple 3 : Regle metier complexe
// Validation : Remise seulement pour les clients Premiumvalidation validateDiscount on save { field Discount, CustomerId;}METHOD validateDiscount. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( CustomerId Discount TotalPrice ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
" Charger les categories clients SELECT Customer, CustomerClassification FROM I_Customer FOR ALL ENTRIES IN @lt_travel WHERE Customer = @lt_travel-CustomerId INTO TABLE @DATA(lt_customers).
LOOP AT lt_travel INTO DATA(ls_travel).
" Regle : > 10% de remise seulement pour clients Premium (Categorie 'A') IF ls_travel-Discount > 10.
DATA(ls_customer) = VALUE #( lt_customers[ Customer = ls_travel-CustomerId ] OPTIONAL ).
IF ls_customer-CustomerClassification <> 'A'.
APPEND VALUE #( %tky = ls_travel-%tky %element-Discount = if_abap_behv=>mk-on ) TO failed-travel.
APPEND VALUE #( %tky = ls_travel-%tky %element-Discount = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Remise superieure a 10% seulement pour clients Premium (actuel : { ls_customer-CustomerClassification })| ) ) TO reported-travel.
ENDIF. ENDIF.
" Regle 2 : Remise max. 50% du prix total IF ls_travel-Discount > ( ls_travel-TotalPrice / 2 ).
APPEND VALUE #( %tky = ls_travel-%tky %element-Discount = if_abap_behv=>mk-on ) TO failed-travel.
APPEND VALUE #( %tky = ls_travel-%tky %element-Discount = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La remise ne peut pas depasser 50% du prix total" ) ) TO reported-travel.
ENDIF.
ENDLOOP.ENDMETHOD.Timing : on modify vs on save
on modify (seulement Determination!)
determination calculate on modify { create; update; }Quand execute :
- ✅ Immediatement apres l’operation CREATE/UPDATE
- ✅ AVANT que la Validation ne s’execute
- ✅ Plusieurs fois possible (a chaque Modify)
Cas d’utilisation :
- Definir les valeurs par defaut immediatement
- Calculer les champs qui sont verifies dans la Validation
- Feedback utilisateur (le champ est rempli immediatement dans l’UI)
on save (Determination & Validation!)
determination finalize on save { update; }validation validateData on save { field Status; }Quand execute :
- ✅ Juste avant le DB-Commit
- ✅ APRES toutes les Determinations on modify
- ✅ Seulement 1 fois par cycle de Save
Cas d’utilisation Determination :
- Calculs finaux (ex. checksums)
- Champs d’audit (LastChangedBy, LastChangedAt)
- Attribution de numeros depuis les plages de numeros DB
Cas d’utilisation Validation :
- Verifier les regles metier
- Assurer la coherence
- Valider les cles etrangeres
Ordre d’execution
Action utilisateur : CREATE/UPDATE │ ▼┌───────────────────────────────────────┐│ 1. DETERMINATION on modify (create) │ ← Immediatement└───────────────┬───────────────────────┘ │ ▼┌───────────────────────────────────────┐│ 2. DETERMINATION on modify (update) │ ← A chaque Update└───────────────┬───────────────────────┘ │ ▼┌───────────────────────────────────────┐│ Utilisateur : Appeler COMMIT ENTITIES │└───────────────┬───────────────────────┘ │ ▼┌───────────────────────────────────────┐│ 3. DETERMINATION on save │ ← Juste avant la DB└───────────────┬───────────────────────┘ │ ▼┌───────────────────────────────────────┐│ 4. VALIDATION on save │ ← Verifications└───────────────┬───────────────────────┘ │ ├─ Erreur? → ROLLBACK, l'utilisateur voit le message d'erreur │ ▼ Succes┌───────────────────────────────────────┐│ 5. INSERT/UPDATE dans la base de donnees │ ← Persistant!└───────────────────────────────────────┘Exemple avec les deux :
define behavior for ZI_Travel alias Travel{ create; update;
// Etape 1 : Definir le status immediatement determination setInitialStatus on modify { create; }
// Etape 2 : Recalculer lors d'un changement de champ determination calculateTotal on modify { field BeginDate, EndDate; }
// Etape 3 : Valeurs finales avant le Save determination setApprovalData on save { update; }
// Etape 4 : Validations validation validateDates on save { field BeginDate, EndDate; } validation validateCustomer on save { field CustomerId; }}Concevoir correctement les messages d’erreur
Niveaux de severite
" ERROR : Bloque le Save%msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La date de fin doit etre apres la date de debut")
" WARNING : Permet le Save, affiche un avertissement%msg = new_message_with_text( severity = if_abap_behv_message=>severity-warning text = 'Le voyage est tres court (< 3 jours)")
" INFO : Seulement informatif%msg = new_message_with_text( severity = if_abap_behv_message=>severity-information text = 'La remise a ete appliquee automatiquement")
" SUCCESS : Confirmation positive%msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = 'Voyage approuve avec succes")Message avec Message Class
" Au lieu de texte code en dur → Utiliser une Message ClassAPPEND VALUE #( %tky = ls_travel-%tky %element-EndDate = if_abap_behv=>mk-on %msg = new_message( id = 'ZTRAVEL_MSG' " Message Class (SE91) number = '001' " Message Number severity = if_abap_behv_message=>severity-error v1 = ls_travel-BeginDate " Parametre &1 v2 = ls_travel-EndDate " Parametre &2 )) TO reported-travel.
" Dans SE91 : Message ZTRAVEL_MSG/001" Texte : "La date de fin &2 doit etre apres la date de debut &1"Marquer plusieurs champs
" L'erreur concerne BeginDate ET EndDateAPPEND VALUE #( %tky = ls_travel-%tky %element-BeginDate = if_abap_behv=>mk-on %element-EndDate = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Periode de voyage invalide" )) TO reported-travel.
" L'UI marque LES DEUX champs en rougeBonnes pratiques
✅ A FAIRE : Determinations
" ✅ Definir des valeurs, ne pas verifierMETHOD setDefaults. MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( Status Currency ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'O" Currency = 'EUR' ) ).ENDMETHOD.
" ✅ on modify pour le feedback utilisateurdetermination calculatePrice on modify { field Quantity, UnitPrice; }" → L'utilisateur voit immediatement le nouveau prix
" ✅ on save pour les valeurs finalesdetermination generateDocumentNumber on save { create; }" → Le numero est attribue seulement lors du Save final✅ A FAIRE : Validations
" ✅ Seulement verifier, ne pas modifierMETHOD validateAmount. READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel FIELDS ( Amount ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel) WHERE Amount <= 0. APPEND VALUE #( %tky = ls_travel-%tky ) TO failed-travel. APPEND VALUE #( %tky = ls_travel-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Le montant doit etre superieur a 0" ) ) TO reported-travel. ENDLOOP.ENDMETHOD.
" ✅ Performance : Bulk-Read au lieu de boucleSELECT Customer FROM I_Customer FOR ALL ENTRIES IN @lt_travel WHERE Customer = @lt_travel-CustomerId INTO TABLE @DATA(lt_valid).
" ✅ Messages d'erreur explicitestext = |Le client { ls_travel-CustomerId } n'existe pas dans le systeme|" Au lieu de : "Validation echouee"❌ A NE PAS FAIRE
" ❌ NE PAS modifier dans une ValidationMETHOD validateData. " FAUX : Une Validation ne doit PAS modifier! MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( Status ) WITH ... " → Peut causer des incoherences!ENDMETHOD.
" ❌ NE PAS verifier et abandonner dans une DeterminationMETHOD setDefaults. IF ls_travel-Amount <= 0. " FAUX : Une Determination ne devrait pas valider! APPEND ... TO failed-travel. " ❌ Utilisez une Validation! ENDIF.ENDMETHOD.
" ❌ NE PAS utiliser on modify pour les acces DBdetermination getCustomerData on modify { field CustomerId; }" → A chaque modification du champ = appel DB" → Mieux : on save (seulement 1x avant le Commit)
" ❌ NE PAS utiliser des messages d'erreur generiquestext = 'Erreur' " ❌ Pas utiletext = 'Validation failed' " ❌ Quel est le probleme?" → Concret : "La date de fin doit etre apres la date de debut"Tests
CLASS ltc_determinations DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION. DATA mo_env TYPE REF TO if_cds_test_environment. METHODS: setup, teardown, test_set_initial_status FOR TESTING, test_calculate_total FOR TESTING.ENDCLASS.
CLASS ltc_determinations IMPLEMENTATION.
METHOD setup. mo_env = cl_cds_test_environment=>create( i_for_entity = 'ZI_Travel' ). ENDMETHOD.
METHOD test_set_initial_status. " Arrange : Creer un Travel sans Status MODIFY ENTITIES OF zi_travel ENTITY Travel CREATE FIELDS ( AgencyId CustomerId ) WITH VALUE #( ( %cid = 'T1' AgencyId = '001' CustomerId = '042' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES.
" Act : La Determination devrait avoir defini le Status READ ENTITIES OF zi_travel ENTITY Travel FIELDS ( Status ) WITH VALUE #( ( %cid = 'T1' ) ) RESULT DATA(lt_travel).
" Assert : Status = 'O" cl_abap_unit_assert=>assert_equals( exp = 'O" act = lt_travel[ 1 ]-Status msg = 'La Determination devrait definir le Status a O" ). ENDMETHOD.
METHOD test_calculate_total. " Test pour la determination de calcul " ... (analogue a ci-dessus) ENDMETHOD.
METHOD teardown. ROLLBACK ENTITIES. mo_env->destroy( ). ENDMETHOD.
ENDCLASS.
CLASS ltc_validations DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION. DATA mo_env TYPE REF TO if_cds_test_environment. METHODS: setup, test_validate_dates_error FOR TESTING, test_validate_dates_success FOR TESTING.ENDCLASS.
CLASS ltc_validations IMPLEMENTATION.
METHOD setup. mo_env = cl_cds_test_environment=>create( i_for_entity = 'ZI_Travel' ). ENDMETHOD.
METHOD test_validate_dates_error. " Arrange : EndDate < BeginDate MODIFY ENTITIES OF zi_travel ENTITY Travel CREATE FIELDS ( BeginDate EndDate ) WITH VALUE #( ( %cid = 'T1" BeginDate = '20250615" EndDate = '20250601' ) ) " FAUX! FAILED DATA(failed).
COMMIT ENTITIES RESPONSE OF zi_travel FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" Assert : Erreur attendue cl_abap_unit_assert=>assert_not_initial( act = commit_failed-travel msg = 'La Validation devrait signaler une erreur" ).
" Verifier le message cl_abap_unit_assert=>assert_bound( act = commit_reported-travel[ 1 ]-%msg msg = 'Un message d erreur devrait etre present" ). ENDMETHOD.
METHOD test_validate_dates_success. " Arrange : Donnees correctes MODIFY ENTITIES OF zi_travel ENTITY Travel CREATE FIELDS ( BeginDate EndDate ) WITH VALUE #( ( %cid = 'T1" BeginDate = '20250601" EndDate = '20250615' ) ) FAILED DATA(failed).
COMMIT ENTITIES RESPONSE OF zi_travel FAILED DATA(commit_failed).
" Assert : Pas d'erreur cl_abap_unit_assert=>assert_initial( act = commit_failed-travel msg = 'La Validation devrait reussir" ). ENDMETHOD.
ENDCLASS.Notes importantes / Bonnes pratiques
- Determination = Definir, Validation = Verifier : Ne jamais melanger!
- Respecter le timing :
on modifypour un feedback immediat,on savepour les operations finales - La Validation ne doit PAS modifier : Seulement lire et remplir FAILED/REPORTED
- Performance : Operations en masse au lieu de boucles avec des appels DB individuels
- Messages explicites : Decrire concretement ce qui est faux
- Marquer %element : Montre a l’utilisateur exactement quel champ pose probleme
- IN LOCAL MODE : Toujours utiliser dans les Behavior Implementations
- Bonne severite : ERROR bloque, WARNING permet le Save
- Utiliser les Message Classes : Au lieu de textes codes en dur → Traductibilite
- Ordre : Determinations → Validations → DB Save
- Tester : Ecrire des tests unitaires pour CHAQUE Determination et Validation
- Collecter les erreurs : Signaler toutes les erreurs d’un coup, ne pas abandonner a la premiere
Ressources supplementaires
- Bases RAP : /rap-basics/
- Guide EML : /eml-entity-manipulation-language/
- Test Doubles : /test-doubles-mocking/
- RAP Managed vs Unmanaged : /rap-managed-vs-unmanaged/