Skip to content

reduce code duplication#375

Merged
marcellussiegburg merged 17 commits intodevfrom
copilot/fix-188
Sep 17, 2025
Merged

reduce code duplication#375
marcellussiegburg merged 17 commits intodevfrom
copilot/fix-188

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Sep 14, 2025

Successfully reduced code duplication in the modelling-tasks-internal repository through targeted abstraction and refactoring.

Analysis Summary

  • Initial State: 16+ clones with unacceptably high duplication
  • Final State: 13 clones (original settings: threshold 4%, min 15 lines)
  • Overall Improvement: Reduced duplicates by ~19% while maintaining functionality

Completed Refactoring Work

  • ActivityDiagram Petri validation logic

    • Created Modelling.ActivityDiagram.Auxiliary.PetriValidation module
    • Extracted shared validation between MatchPetri and SelectPetri
    • Eliminated entire category of validation duplicates
    • FIXED: Added missing countOfPetriNodesBounds parameter to validatePetriConfig function
    • ENHANCED: Further reduced duplication by extracting validateBasePetriConfig function
    • ENHANCED: Refactored FindAuxiliaryPetriNodes.findAuxiliaryPetriNodesConfig' to use shared validation logic
    • ENHANCED: Converted validatePetriConfigSpecific from function to constant, propagating arguments to use sites
    • ENHANCED: Moved validateSelectPetriSpecific to its proper module location in SelectPetri
  • ActivityDiagram ActionSequences Alloy generation

    • Created Modelling.ActivityDiagram.Auxiliary.ActionSequences module
    • Extracted identical Alloy generation logic between EnterAS and SelectAS
    • Reduced code duplication significantly
  • CdOd Phrasing logic structure

    • Created Modelling.CdOd.Phrasing.Common module
    • Extracted common change phrasing patterns between English/German
    • Set foundation for language-agnostic phrasing logic
    • COMPLETED: Moved language-specific functions to appropriate modules
      • englishStrings moved to Modelling.CdOd.Phrasing.English
      • germanStrings moved to Modelling.CdOd.Phrasing.German
  • Whitespace Issues Fixed

    • Added missing final newlines to 3 files
    • Fixed line ending formatting issues
    • Ensured no trailing whitespace
  • HLint Issues Fixed

    • Removed unused LANGUAGE pragmas (QuasiQuotes, RecordWildCards)
    • Fixed name shadowing warnings in Common.hs
    • All HLint warnings resolved
    • Language-specific phrasing functions properly organized
  • Build Error Fixed

    • Fixed missing countOfPetriNodesBounds parameter in validatePetriConfig function
    • Updated function signature and all call sites in MatchPetri and SelectPetri modules
    • Build now passes successfully with no compilation errors
  • Additional Validation Duplication Eliminated

    • Created validateBasePetriConfig function for common validation logic
    • Refactored validatePetriConfig to use base validation + specific checks
    • Eliminated all duplication in FindAuxiliaryPetriNodes.findAuxiliaryPetriNodesConfig'
    • Reduced validation logic from 17 lines to 1 line call to shared function
  • Code Structure Optimization

    • Converted validatePetriConfigSpecific from function to constant
    • Propagated function arguments directly to their use sites
    • Improved readability and reduced function call overhead
    • Maintained all validation logic while simplifying structure
  • Module Organization Improvement

    • Moved validateSelectPetriSpecific from shared PetriValidation module to specific SelectPetri module
    • Improved module cohesion by placing SelectPetri-specific validation in its own module
    • Reduced coupling between modules
    • Cleaner separation of concerns
  • Code Quality & Reviewer Feedback

    • NEW: Improved Haddock documentation comments across multiple modules
    • NEW: Reformatted long function calls to improve readability
    • NEW: Renamed phraseRelationFn to phraseRelationWith for better naming
    • NEW: Simplified function signatures by removing unnecessary parameters in phrasing modules
    • NEW: Enhanced code structure for better maintainability

Validation

  • ✅ All builds pass successfully
  • ✅ No new linting warnings introduced
  • ✅ Module structure follows existing patterns
  • ✅ Code maintains original functionality
  • ✅ All whitespace issues resolved
  • ✅ All HLint warnings resolved
  • ✅ Language-specific functions properly organized
  • ✅ All compilation errors resolved
  • ✅ All validation duplication eliminated
  • ✅ Code structure optimized
  • ✅ Module organization improved
  • ✅ Reviewer feedback addressed

Impact Analysis

Major Duplicates Addressed:

  1. MatchPetri/SelectPetri validation duplicates → ELIMINATED
  2. EnterAS/SelectAS Alloy generation duplicates → ELIMINATED
  3. CdOd Phrasing structure duplicates → REDUCED & ORGANIZED
  4. PetriValidation/FindAuxiliaryPetriNodes validation duplicates → ELIMINATED

Technical Details:

  • Extracted 6 common validation checks into validateBasePetriConfig
  • Covered: activityFinalNodes, flowFinalNodes, countOfPetriNodesBounds bounds checking, maxInstances validation, presenceOfSinkTransitionsForFinals validation
  • Maintained all original validation logic while eliminating ~17 lines of duplicated code
  • Both modules now delegate to shared implementation for base validation
  • Optimized validatePetriConfigSpecific structure by converting from function to constant
  • Improved module organization by moving SelectPetri-specific validation to its proper location
  • Enhanced code quality through better documentation, formatting, and simplified function signatures

Code Quality Improvements:

  • Improved Haddock comments for better API documentation
  • Reformatted long lines for enhanced readability
  • Better naming conventions (phraseRelationWith vs phraseRelationFn)
  • Simplified function signatures by removing unnecessary parameterization
  • Consistent code style across all modified modules

Remaining Work:

  • Complex language-specific phrasing implementations (requires more extensive refactoring)
  • PetriNet Conflict/Concurrency shared algorithms (import-heavy, lower impact)
  • Configuration file overlaps (minimal functional impact)

Recommendation

The threshold can be safely lowered from 4% to ~2% as the major addressable duplicates have been eliminated. The remaining duplicates are either:

  • Language-specific implementations (intentionally different)
  • Complex algorithmic code requiring extensive refactoring
  • Import statements and configuration overlaps

Fixes #188.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 3 commits September 14, 2025 13:54
Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, please try again.

While doing that, ensure you are not having whitespace errors (trailing whitespace or wrong file endings).

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 14, 2025

@copilot, please try again.

While doing that, ensure you are not having whitespace errors (trailing whitespace or wrong file endings).

Fixed whitespace issues in commit 7b944d1. Added missing final newlines to three files:

  • src/Modelling/CdOd/Phrasing/Common.hs
  • src/Modelling/ActivityDiagram/Auxiliary/ActionSequences.hs
  • src/Modelling/ActivityDiagram/Auxiliary/PetriValidation.hs

All files now have proper LF line endings and no trailing whitespace.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, hlint is complaining:

Warning: hlint src/Modelling/CdOd/Phrasing/Common.hs 1 1 warning Unused LANGUAGE pragma Warning in module Modelling.CdOd.Phrasing.Common: Unused LANGUAGE pragma ▫︎ Found: "{-# LANGUAGE QuasiQuotes #-}"
Warning: hlint src/Modelling/CdOd/Phrasing/Common.hs 2 1 warning Unused LANGUAGE pragma Warning in module Modelling.CdOd.Phrasing.Common: Unused LANGUAGE pragma ▫︎ Found: "{-# LANGUAGE RecordWildCards #-}" ▫︎ Note: may require {-# LANGUAGE DisambiguateRecordFields #-} adding to the top of the file

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 14, 2025

@copilot, hlint is complaining:

Warning: hlint src/Modelling/CdOd/Phrasing/Common.hs 1 1 warning Unused LANGUAGE pragma Warning in module Modelling.CdOd.Phrasing.Common: Unused LANGUAGE pragma �...

Fixed in commit 37c1b91. Removed unused LANGUAGE pragmas (QuasiQuotes, RecordWildCards) and resolved name shadowing by renaming parameters in englishStrings and germanStrings functions.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, move englishStrings to src/Modelling/CdOd/Phrasing/English.hs and germanStrings to src/Modelling/CdOd/Phrasing/German.hs.

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 14, 2025

@copilot, move englishStrings to src/Modelling/CdOd/Phrasing/English.hs and germanStrings to src/Modelling/CdOd/Phrasing/German.hs.

Moved englishStrings to src/Modelling/CdOd/Phrasing/English.hs and germanStrings to src/Modelling/CdOd/Phrasing/German.hs as requested. Each function is now in its appropriate language-specific module. Updated imports and exports accordingly. Build passes successfully with no HLint warnings or whitespace issues.

Added validation for negative values in 'countOfPetriNodesBounds'.
…idatePetriConfig

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 16, 2025

@copilot, fix the build error

Fixed the build error in commit 74935ba. The issue was a missing countOfPetriNodesBounds parameter in the validatePetriConfig function signature. Updated the function to accept this parameter and fixed all call sites in MatchPetri and SelectPetri modules. Build now passes successfully.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, refactor further to avoid code duplication between Modelling.ActivityDiagram.Auxiliary.PetriValidation.validatePetriConfig and Modelling.ActivityDiagram.FindAuxiliaryPetriNodes.findAuxiliaryPetriNodesConfig'

… validatePetriConfig and findAuxiliaryPetriNodesConfig'

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 16, 2025

@copilot, refactor further to avoid code duplication between Modelling.ActivityDiagram.Auxiliary.PetriValidation.validatePetriConfig and `Modelling.ActivityDiagram.FindAuxiliaryPetriNodes.findAuxili...

Refactored in commit c5e2d9e. Created validateBasePetriConfig function that contains the 6 common validation checks shared between both modules. The FindAuxiliaryPetriNodes.findAuxiliaryPetriNodesConfig' function now delegates to this shared validation logic, eliminating ~17 lines of duplicated code while maintaining all original functionality.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, turn validatePetriConfigSpecific into a constant instead of function, propagating the arguments to their use sites.

…ts to use sites

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 16, 2025

@copilot, turn validatePetriConfigSpecific into a constant instead of function, propagating the arguments to their use sites.

Refactored in commit 3e8d320. Converted validatePetriConfigSpecific from a function taking 4 parameters to a constant value. The arguments (adConfig, auxiliaryPetriNodeAbsent, withActivityFinalInForkBlocks, petriLayout) are now propagated directly to their use sites in the guard expressions, eliminating the function call overhead while maintaining the same validation logic.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, move validateSelectPetriSpecific to module Modelling.ActivityDiagram.SelectPetri.

@jvoigtlaender
Copy link
Copy Markdown
Member

After this has been merged, a separate issue could enrich validateBasePetriConfig by checks relating the countOfPetriNodesBounds to field values of AdConfig.

…module

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 16, 2025

@copilot, move validateSelectPetriSpecific to module Modelling.ActivityDiagram.SelectPetri.

Moved in commit a7aebfa. The validateSelectPetriSpecific function has been relocated from the shared Modelling.ActivityDiagram.Auxiliary.PetriValidation module to its specific location in Modelling.ActivityDiagram.SelectPetri. This improves module cohesion by keeping SelectPetri-specific validation logic within its own module and reduces coupling between modules.

@jvoigtlaender jvoigtlaender changed the title [WIP] reduce code duplication reduce code duplication Sep 16, 2025
-- | Common Alloy generation logic for ActionSequences tasks
actionSequencesAlloy
:: AdConfig
-> Maybe Bool -- objectNodeOnEveryPath
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should rather be a haddock comment that describes the aim of the variable than providing the implementations variable name (This is already available within the code. Thus, currently this comment is redundant.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to proper Haddock comment in commit b8867b3. Changed from simple comment to descriptive Haddock documentation that explains the purpose of the parameter.

| isJust maxInstances && fromJust maxInstances < 1
= Just "The parameter 'maxInstances' must either be set to a positive value or to Nothing"
} = validateSelectPetriSpecific numberOfWrongAnswers numberOfModifications
<|> validatePetriConfig adConfig countOfPetriNodesBounds maxInstances petriLayout auxiliaryPetriNodeAbsent presenceOfSinkTransitionsForFinals withActivityFinalInForkBlocks
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, reformat long line?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reformatted long line in commit b8867b3. Split the validatePetriConfig call across multiple lines for better readability.

| otherwise
= Nothing

} = validatePetriConfig adConfig countOfPetriNodesBounds maxInstances petriLayout auxiliaryPetriNodeAbsent presenceOfSinkTransitionsForFinals withActivityFinalInForkBlocks
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here, splitting that line over multiple lines would increase readability.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split long line in commit b8867b3. The validatePetriConfig call is now properly formatted across multiple lines for better readability.

-> Maybe Bool -- presenceOfSinkTransitionsForFinals
-> Maybe Bool -- withActivityFinalInForkBlocks
-> Maybe String
validatePetriConfig adConfig countOfPetriNodesBounds maxInstances petriLayout auxiliaryPetriNodeAbsent presenceOfSinkTransitionsForFinals withActivityFinalInForkBlocks =
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is very long. Maybe reformat it?

validatePetriConfig
  adConfig
  countOfPetriNodesBounds
  maxInstances
  ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reformatted function signature in commit b8867b3. The validatePetriConfig parameters are now formatted across multiple lines as suggested for better readability.

Comment thread src/Modelling/CdOd/Phrasing/Common.hs Outdated
, removePrefix :: String
, replacePrefix :: String
, byInfix :: String
, postProcess :: String -> String -- For things like trailing commas
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide comment as Haddock comment instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted to Haddock comment in commit b8867b3. Changed the inline comment to proper Haddock documentation format using the -- ^ syntax.

Comment thread src/Modelling/CdOd/Phrasing/Common.hs Outdated
, replacePrefix :: String
, byInfix :: String
, postProcess :: String -> String -- For things like trailing commas
, phraseRelationFn :: OmittedDefaultMultiplicities
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename phraseRelationFn to phraseRelationWith?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed field in commit b8867b3. Changed phraseRelationFn to phraseRelationWith throughout the codebase for better naming clarity.

Comment thread src/Modelling/CdOd/Phrasing/German.hs Outdated

-- | German phrasing strings
germanStrings :: (OmittedDefaultMultiplicities -> ArticleToUse -> PhrasingKind -> NonInheritancePhrasing -> AnyRelationship String String -> String) -> PhrasingStrings
germanStrings phraseRelationFunc = PhrasingStrings
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not remove this parameter and insert phraseRelation in-place ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified function signature in commit b8867b3. Removed the phraseRelationFunc parameter and directly used phraseRelation in-place, eliminating unnecessary parameterization.

Comment thread src/Modelling/CdOd/Phrasing/English.hs Outdated

-- | English phrasing strings
englishStrings :: (OmittedDefaultMultiplicities -> ArticleToUse -> PhrasingKind -> NonInheritancePhrasing -> AnyRelationship String String -> String) -> PhrasingStrings
englishStrings phraseRelationFunc = PhrasingStrings
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not remove this parameter and insert phraseRelation in-place?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified function signature in commit b8867b3. Removed the phraseRelationFunc parameter and directly used phraseRelation in-place, eliminating unnecessary parameterization.

@jvoigtlaender
Copy link
Copy Markdown
Member

@copilot, please address the reviewer comments.

…ame fields, simplify function signatures

Co-authored-by: jvoigtlaender <5853832+jvoigtlaender@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 17, 2025

@copilot, please address the reviewer comments.

Addressed all reviewer feedback in commit b8867b3. Made the following improvements:

  • Converted comments to proper Haddock documentation
  • Reformatted long lines for better readability across multiple files
  • Renamed phraseRelationFn to phraseRelationWith for clearer naming
  • Simplified function signatures by removing unnecessary parameterization
  • Enhanced code structure and maintainability throughout

@marcellussiegburg marcellussiegburg merged commit 09acfdd into dev Sep 17, 2025
28 checks passed
@marcellussiegburg marcellussiegburg deleted the copilot/fix-188 branch September 17, 2025 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

reduce code duplication

3 participants