refactor(planner): extract MAX_VARIETY_SCORE constant in PlanningService

Replaces magic literal 10.0 with a named constant in all four
scoring sites: getSuggestions, getVarietyPreview, scoreFromSimulatedSlots,
and getVarietyScore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 12:09:08 +02:00
committed by marcel
parent b45ab0fd46
commit 8051fcbe22

View File

@@ -26,6 +26,8 @@ import java.util.stream.Collectors;
@Service @Service
public class PlanningService { public class PlanningService {
private static final double MAX_VARIETY_SCORE = 10.0;
private final WeekPlanRepository weekPlanRepository; private final WeekPlanRepository weekPlanRepository;
private final WeekPlanSlotRepository weekPlanSlotRepository; private final WeekPlanSlotRepository weekPlanSlotRepository;
private final CookingLogRepository cookingLogRepository; private final CookingLogRepository cookingLogRepository;
@@ -138,7 +140,7 @@ public class PlanningService {
List<SimulatedSlot> currentSlots = plan.getSlots().stream() List<SimulatedSlot> currentSlots = plan.getSlots().stream()
.map(s -> new SimulatedSlot(s.getRecipe(), s.getSlotDate())) .map(s -> new SimulatedSlot(s.getRecipe(), s.getSlotDate()))
.toList(); .toList();
double currentScore = currentSlots.isEmpty() ? 10.0 double currentScore = currentSlots.isEmpty() ? MAX_VARIETY_SCORE
: scoreFromSimulatedSlots(currentSlots, config, recentlyCookedIds); : scoreFromSimulatedSlots(currentSlots, config, recentlyCookedIds);
List<Recipe> allRecipes = recipeRepository.findByHouseholdIdAndDeletedAtIsNull(householdId); List<Recipe> allRecipes = recipeRepository.findByHouseholdIdAndDeletedAtIsNull(householdId);
@@ -202,7 +204,7 @@ public class PlanningService {
List<SimulatedSlot> currentSlots = plan.getSlots().stream() List<SimulatedSlot> currentSlots = plan.getSlots().stream()
.map(s -> new SimulatedSlot(s.getRecipe(), s.getSlotDate())) .map(s -> new SimulatedSlot(s.getRecipe(), s.getSlotDate()))
.toList(); .toList();
double currentScore = currentSlots.isEmpty() ? 10.0 double currentScore = currentSlots.isEmpty() ? MAX_VARIETY_SCORE
: scoreFromSimulatedSlots(currentSlots, config, recentlyCookedIds); : scoreFromSimulatedSlots(currentSlots, config, recentlyCookedIds);
double projectedScore = simulateVarietyScore(plan, candidate, date, config, recentlyCookedIds); double projectedScore = simulateVarietyScore(plan, candidate, date, config, recentlyCookedIds);
@@ -255,12 +257,12 @@ public class PlanningService {
.mapToLong(c -> c - 1) .mapToLong(c -> c - 1)
.sum(); .sum();
double score = 10.0; double score = MAX_VARIETY_SCORE;
score -= tagRepeatCount * wTagRepeat; score -= tagRepeatCount * wTagRepeat;
score -= ingredientOverlapCount * wIngredientOverlap; score -= ingredientOverlapCount * wIngredientOverlap;
score -= recentRepeatCount * wRecentRepeat; score -= recentRepeatCount * wRecentRepeat;
score -= duplicatePenaltyCount * wPlanDuplicate; score -= duplicatePenaltyCount * wPlanDuplicate;
return Math.max(0, Math.min(10, score)); return Math.max(0, Math.min(MAX_VARIETY_SCORE, score));
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@@ -349,12 +351,12 @@ public class PlanningService {
} }
// Calculate score // Calculate score
double score = 10.0; double score = MAX_VARIETY_SCORE;
score -= tagRepeats.size() * wTagRepeat; score -= tagRepeats.size() * wTagRepeat;
score -= overlaps.size() * wIngredientOverlap; score -= overlaps.size() * wIngredientOverlap;
score -= recentRepeats.size() * wRecentRepeat; score -= recentRepeats.size() * wRecentRepeat;
score -= duplicatePenaltyCount * wPlanDuplicate; score -= duplicatePenaltyCount * wPlanDuplicate;
score = Math.max(0, Math.min(10, score)); score = Math.max(0, Math.min(MAX_VARIETY_SCORE, score));
return new VarietyScoreResponse(score, tagRepeats, overlaps, recentRepeats, duplicatesInPlan); return new VarietyScoreResponse(score, tagRepeats, overlaps, recentRepeats, duplicatesInPlan);
} }