principlerubyrailsMinor
Strategy to reduce duplicate code in many similar modules
Viewed 0 times
modulesstrategyduplicatereducemanycodesimilar
Problem
The Situation
I have created some code in the form of modules that each represent a medical questionnaire (I'm calling them
These
There are 2 examples for reference at the bottom that illustrate the problem of duplication... much of the code is similar but not exactly the same.
The Problem
There is a lot of duplication here, but I'm not sure about the best strategy to remove it. There are a few things that make it difficult for this particular problem and make me lean towards accepting some duplication as opposed to a system that is too strict to work. The system needs to remain flexible enough to accommodate currently unknown medical questionnaires of a similar nature so I need to be careful (the reason I've gone with a
Here are some examples:
The Question:
What strategies might be employed here to reduce duplication overall? I'm not looking for tweaks cut out a few lines from these specific examples. Implementation cost is a considerat
I have created some code in the form of modules that each represent a medical questionnaire (I'm calling them
Catalogs). Each different questionnaire has its own module as they may differ slightly in their content and associated calculations, but are essentially made up of simple questions that have boolean/numeric possible responses. Here is an example.These
Catalog modules are included in an Entry class that collects responses matching the question names. Each questionnaire is transformed into a DEFINITION which is used in the Entry to do things like:- Validate inputs
- Check completeness
- Calculate scoring
There are 2 examples for reference at the bottom that illustrate the problem of duplication... much of the code is similar but not exactly the same.
The Problem
There is a lot of duplication here, but I'm not sure about the best strategy to remove it. There are a few things that make it difficult for this particular problem and make me lean towards accepting some duplication as opposed to a system that is too strict to work. The system needs to remain flexible enough to accommodate currently unknown medical questionnaires of a similar nature so I need to be careful (the reason I've gone with a
Module system so far)Here are some examples:
- Each
Catalogcan have slightly different scoring requirements and custom grouping of questions that represent one "score"
- Potentially many
Catalogs are included in anEntryclass and can't step on each other
- Some
Catalogs incorporate things like "Current Weight" for calculations, breaking the 1-5 or 1-10 paradigm and not fitting very nicely into simplesumreductions.
- One
Catalogrequires a week of previous entries in order to be valid, a sort of weird custom validation.
The Question:
What strategies might be employed here to reduce duplication overall? I'm not looking for tweaks cut out a few lines from these specific examples. Implementation cost is a considerat
Solution
You mention in your description that
This violates the single responsibility principle.
Validating can largely be avoided, because in
A validator object can validate an
A scoring object can then score an
Thinking about validation more, it actually is hardly necessary. Entry defines exactly which the exact
A good term to google for if you want some help with the meta-programming is DSL (Domain Specific Language).
Entry will do three different things:- Validate inputs
- Check completeness
- Calculate scoring
This violates the single responsibility principle.
Entry does too much! I suggest a system where Entry is just an accumulation of answers with a general API to retrieve questions and their answers. Ideally it would use some meta-programming to make the code simpler and self-documenting.class HBI
include Questionnaire
select(:general_wellbeing) do |s|
s.option(:no_difficulty, 0, :optional => :stuff)
s.option(:slightly_below_par, 1, :optional => :stuff)
# etc
end
end
hbi = HBI.new
hbi.answer(:general_wellbeing, 1, :optional => :stuff)
hbi.general_wellbeing # => 1 or for example an Answer object
Validating can largely be avoided, because in
Entry you define which values are acceptable as answers. Simply raise an error in Entry#answer when receiving a non-sensical value (such as 10). You still need to check for completeness, though. A validator object can validate an
Entry. You could use some more meta-programming here to avoid repetition or use a library like scrivener.class HBIValidator
def initialize(entry)
@entry = entry
end
def validate
assert_presence(:well_being)
# etc
end
end
validator = HBIValidator.new(hbi)
validator.valid? # => true or false
A scoring object can then score an
Entry. Again you could use some meta-programming here to avoid repetition.Thinking about validation more, it actually is hardly necessary. Entry defines exactly which the exact
scorer = HBIScorer.new(hbi)
scorer.score # => 10 or for example a Score object.A good term to google for if you want some help with the meta-programming is DSL (Domain Specific Language).
Code Snippets
scorer = HBIScorer.new(hbi)
scorer.score # => 10 or for example a Score object.Context
StackExchange Code Review Q#77877, answer score: 2
Revisions (0)
No revisions yet.