Skip to content

Refactor: consolidate duplicated code clusters identified in static analysis #2701

@timjarsky

Description

@timjarsky

Summary

A repository-wide duplicate-code analysis was performed across Packages/MIES/*.ipf. It identified 15 clusters of near-duplicate functions, ranked by a Duplicate Risk Score (S × L × N × D × C, where S=similarity, L=normalized length, N=occurrences, D=module spread, C=complexity). This issue tracks consolidation of the highest-impact clusters.

The biggest risks are not lines of code, but divergence risk — when an algorithm is duplicated and a future bug fix is applied to only one copy.

Top duplicate clusters

Rank Cluster File Score
1 GetLBRowCache / GetLBIndexCache MIES_WaveDataFolderGetters.ipf (~2223–2382) 5.52
2 55× GetXxx() / GetXxxAsString() DF getter pairs MIES_WaveDataFolderGetters.ipf 2.61
3 GetLastSettingEach{RAC,SCI,TextRAC,TextSCI} MIES_MiesUtilities_Logbook.ipf (~1011–1272) 2.59
4 SFO_Operation{Div,Minus,Mult,Plus}ImplDataSets MIES_SweepFormula_Operations.ipf (~1094–2063) 2.51
5 SFO_Operation{RMS,Stdev,Variance,Max,Min} scaffolds MIES_SweepFormula_Operations.ipf (~1792–2527) 2.23
6 GetLastSetting{RAC,SCI,TextRAC,TextSCI} MIES_MiesUtilities_Logbook.ipf (~893–1135) 2.21
7 GetDA_EphysGuiState{Num,TxT} MIES_WaveDataFolderGetters.ipf (~6085–6225) 1.77
8 GetLastSettingIndep{RAC,SCI,TextIndepRAC,TextIndepSCI} MIES_MiesUtilities_Logbook.ipf (~326–418) 1.73
9 GetSweepSettingsWave / GetSweepSettingsTextWave MIES_WaveDataFolderGetters.ipf (~2457–2905) 1.10
10 DC_Make{NI,SUTTER}ChannelWave MIES_DataConfigurator.ipf (~417–472) 0.95
11 GetLastSettingIndep / GetLastSettingTextIndep MIES_MiesUtilities_Logbook.ipf (~279–325) 0.53
12 SFO_Operation{Max,Min} entry points MIES_SweepFormula_Operations.ipf (~1792–1943) 0.53
13 GetAnalysLB{NumericalValues,TextualValues,NumericalKeys,TextualKeys} MIES_WaveDataFolderGetters.ipf (~5875–5920) 0.37
14 GetSweepFormula{X,Y} MIES_WaveDataFolderGetters.ipf (~7643–7673) 0.35
15 EnableControls / DisableControls MIES_GuiUtilities.ipf (~81–116) 0.23

Highest priority — divergence-risk fixes

🔴 1. GetLBRowCache / GetLBIndexCache (MIES_WaveDataFolderGetters.ipf)

~83 lines each, ~92% identical. Implements a wave-mod-count-aware labnotebook cache. Differs only in: cache-key helper (CA_CreateLBRowCacheKey vs CA_CreateLBIndexCacheKey), sentinel value (LABNOTEBOOK_GET_RANGE vs LABNOTEBOOK_UNCACHED_VALUE), and wave dimensionality.

Suggested refactor: Extract threadsafe static Function/WAVE GetLBCacheImpl(WAVE values, string key, variable sentinelValue, variable waveDim) and make the two public functions thin wrappers.

🔴 3 & 6 & 8 & 11. The GetLastSetting* family (MIES_MiesUtilities_Logbook.ipf)

Four interacting 2×2 grids ({RAC, SCI} × {numeric, textual}, plus Indep and Each variants — ~14 functions total). Loop bodies are byte-identical except for one AFH_GetSweepsFromSame{RACycle,SCI} call and the wave-type suffix (/D vs /T).

Suggested refactor: Two private impls parameterised by isRACycle / isText:

  • GetLastSettingScanImpl(...) (used by GetLastSetting{RAC,SCI,Text*})
  • GetLastSettingEachImpl(...) (used by the Each variants)

The public functions become 1–2 line wrappers, preserving the existing API.

🟠 4 & 5 & 12. SweepFormula operation duplication (MIES_SweepFormula_Operations.ipf)

  • SFO_Operation{Div,Minus,Mult,Plus}ImplDataSets: four ~27-line functions identical except for one MatrixOp operator. Suggested refactor: SFO_BinaryOpImplDataSets(WAVE/Z d0, WAVE/Z d1, string opSymbol).
  • SFO_Operation{RMS,Stdev,Variance,Max,Min}: five entry-point scaffolds plus their Impl functions sharing an 18-line dispatch/output template. Suggested refactor: A generic SFO_ColReduceEntry(...) plus Impl functions that only carry the unique MatrixOp line.

🟠 7 & 9 & 13 & 14. Numeric/text wave-getter pairs (MIES_WaveDataFolderGetters.ipf)

Pairs that differ only in /D vs /T, the default fill value (NaN vs ""), and one wave-name string. Suggested refactor: Private *Impl(..., variable isText) helpers.

🟠 10. DC_Make{NI,SUTTER}ChannelWave (MIES_DataConfigurator.ipf)

21-line clones differing only in time-unit scaling (MICRO_TO_MILLI / "ms" vs MICRO_TO_ONE / "s"). Suggested refactor: DC_MakeChannelWaveImpl(channel, samplingInterval, hwType) selecting unit by hardware type.

🟡 15. EnableControls / DisableControls (MIES_GuiUtilities.ipf)

Suggested refactor: SetControlsState(win, list, enable); keep existing two functions as one-line wrappers for source compatibility.

Out of scope / "document only"

Cluster 2 (55× GetXxx / GetXxxAsString pairs) is an intentional Igor Pro idiom for data-folder access. Eliminating it would require code generation and isn't recommended; this issue should not attempt to refactor it. We may instead want to add a comment block in MIES_WaveDataFolderGetters.ipf explaining the pattern so it isn't repeatedly flagged by future analyses.

Acceptance criteria

  • Cluster 1 consolidated (GetLBCacheImpl); existing tests pass.
  • Clusters 3, 6, 8, 11 consolidated under shared GetLastSetting*Impl helpers; logbook tests pass.
  • Clusters 4, 5, 12 consolidated in MIES_SweepFormula_Operations.ipf; SweepFormula tests pass.
  • Clusters 7, 9, 13, 14 consolidated where they share WaveLocationMod plumbing.
  • Cluster 10 consolidated in MIES_DataConfigurator.ipf; NI and SUTTER acquisition tests pass.
  • Cluster 15 consolidated in MIES_GuiUtilities.ipf.
  • Public API/signatures preserved for all wrappers (no caller-side changes).
  • Brief comment added near cluster-2 boilerplate explaining the DF-getter idiom.

Notes

  • Each cluster can be addressed in an independent PR; the items above are roughly ordered by risk reduction.
  • The line numbers above were observed during analysis on the current main and may drift slightly as the codebase evolves — verify against the current revision before refactoring.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions