Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Experiment often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Experiment, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class Experiment |
||
20 | { |
||
21 | /** |
||
22 | * The project the Experiment is in |
||
23 | * @var integer |
||
24 | */ |
||
25 | private $projectId; |
||
26 | |||
27 | /** |
||
28 | * List of IDs of all audiences the Experiment is targeted at |
||
29 | * @var array[integer] |
||
30 | */ |
||
31 | private $audienceIds; |
||
32 | |||
33 | /** |
||
34 | * The ID for the Campaign that the Experiment is in |
||
35 | * @var integer |
||
36 | */ |
||
37 | private $campaignId; |
||
38 | |||
39 | /** |
||
40 | * Experiment-level changes that will run before all Variations. Typically |
||
41 | * this is custom CSS or custom JavaScript. |
||
42 | * @var array[Change] |
||
43 | */ |
||
44 | private $changes; |
||
45 | |||
46 | /** |
||
47 | * The time the experiment was initially created |
||
48 | * @var string |
||
49 | */ |
||
50 | private $created; |
||
51 | |||
52 | /** |
||
53 | * The description or hypothesis for an Experiment |
||
54 | * @var string |
||
55 | */ |
||
56 | private $description; |
||
57 | |||
58 | /** |
||
59 | * Percentage expressed as a number from 0-10000 to hold back from being |
||
60 | * included in the experiment |
||
61 | * @var integer |
||
62 | */ |
||
63 | private $holdback; |
||
64 | |||
65 | /** |
||
66 | * Unique string identifier for this experiment within the project. |
||
67 | * @var string |
||
68 | */ |
||
69 | private $key; |
||
70 | |||
71 | /** |
||
72 | * The last time the experiment was modified |
||
73 | * @var string |
||
74 | */ |
||
75 | private $lastModified; |
||
76 | |||
77 | /** |
||
78 | * An ordered list of metrics to track for the experiment |
||
79 | * @var array[Metric] |
||
80 | */ |
||
81 | private $metrics; |
||
82 | |||
83 | /** |
||
84 | * Name of the Experiment |
||
85 | * @var string |
||
86 | */ |
||
87 | private $name; |
||
88 | |||
89 | /** |
||
90 | * The last time the experiment was modified |
||
91 | * @var Schedule |
||
92 | */ |
||
93 | private $schedule; |
||
94 | |||
95 | /** |
||
96 | * Current state of the experiment. Can be 'active', 'paused' or 'archived'. |
||
97 | * @var string |
||
98 | */ |
||
99 | private $status; |
||
100 | |||
101 | /** |
||
102 | * A list of Variations that each define an experience to show in the context |
||
103 | * of the Experiment for the purpose of comparison against each other |
||
104 | * @var array[Variation] |
||
105 | */ |
||
106 | private $variations = array(); |
||
107 | |||
108 | /** |
||
109 | * The unique identifier for the Experiment |
||
110 | * @var integer |
||
111 | */ |
||
112 | private $id; |
||
113 | |||
114 | /** |
||
115 | * Whether or not the Experiment is a classic Experiment |
||
116 | * @var boolean |
||
117 | */ |
||
118 | private $isClassic; |
||
119 | |||
120 | /** |
||
121 | * Indicates whether this is a standalone a/b experiment or an experience within a personalization campaign |
||
122 | * Can be a/b or personalization |
||
123 | * @var string |
||
124 | */ |
||
125 | private $type; |
||
126 | |||
127 | /** |
||
128 | * The audiences that should see this experiment. If the field is null or |
||
129 | * omitted, the experiment will target everyone. Multiple audiences can be |
||
130 | * combined with "and" or "or" using the same structure as audience conditions |
||
131 | * @var string |
||
132 | */ |
||
133 | private $audienceConditions; |
||
134 | |||
135 | /** |
||
136 | * Traffic allocation policy across variations in this experiment |
||
137 | * @var string |
||
138 | */ |
||
139 | private $allocationPolicy; |
||
140 | |||
141 | /** |
||
142 | * The first time the Experiment was activated |
||
143 | * @var type |
||
144 | */ |
||
145 | private $earliest; |
||
146 | |||
147 | /** |
||
148 | * A list of Page IDs used in the Experiment. url_targeting or page_ids, but not both. |
||
149 | */ |
||
150 | private $pageIds; |
||
151 | |||
152 | /** |
||
153 | * The last time the Experiment was activated (not present if it is still activated) |
||
154 | * @var type |
||
155 | */ |
||
156 | private $latest; |
||
157 | |||
158 | /** |
||
159 | * Rules for which URLs this experiment should target. This is an alternative |
||
160 | * to page_ids, for cases when you don't need to reuse an existing page or |
||
161 | * target multiple pages. When creating an experiment any variations without |
||
162 | * a page ID will apply to the URL Targeting page. |
||
163 | * @var type |
||
164 | */ |
||
165 | private $urlTargeting; |
||
166 | |||
167 | /** |
||
168 | * Constructor. |
||
169 | */ |
||
170 | 7 | public function __construct($options = array()) |
|
223 | |||
224 | /** |
||
225 | * Returns this object as array. |
||
226 | */ |
||
227 | 3 | public function toArray() |
|
288 | |||
289 | 5 | public function getProjectId() |
|
293 | |||
294 | 7 | public function setProjectId($projectId) |
|
298 | |||
299 | 4 | public function getAudienceIds() |
|
303 | |||
304 | 7 | public function setAudienceIds($audienceIds) |
|
308 | |||
309 | 4 | public function getCampaignId() |
|
313 | |||
314 | 7 | public function setCampaignId($campaignId) |
|
318 | |||
319 | 4 | public function getChanges() |
|
323 | |||
324 | 7 | public function setChanges($changes) |
|
328 | |||
329 | 4 | public function getCreated() |
|
333 | |||
334 | 5 | public function setCreated($created) |
|
338 | |||
339 | 4 | public function getDescription() |
|
343 | |||
344 | 7 | public function setDescription($description) |
|
348 | |||
349 | 4 | public function getHoldback() |
|
353 | |||
354 | 7 | public function setHoldback($holdback) |
|
358 | |||
359 | 4 | public function getKey() |
|
363 | |||
364 | 7 | public function setKey($key) |
|
368 | |||
369 | 4 | public function getLastModified() |
|
373 | |||
374 | 5 | public function setLastModified($lastModified) |
|
378 | |||
379 | 4 | public function getMetrics() |
|
383 | |||
384 | 7 | public function setMetrics($metrics) |
|
388 | |||
389 | 7 | public function getName() |
|
393 | |||
394 | 7 | public function setName($name) |
|
398 | |||
399 | 4 | public function getSchedule() |
|
403 | |||
404 | 7 | public function setSchedule($schedule) |
|
408 | |||
409 | 4 | public function getStatus() |
|
413 | |||
414 | 7 | public function setStatus($status) |
|
418 | |||
419 | 4 | public function getVariations() |
|
423 | |||
424 | 7 | public function setVariations($variations) |
|
428 | |||
429 | 4 | public function getId() |
|
433 | |||
434 | 5 | public function setId($id) |
|
438 | |||
439 | 4 | public function getIsClassic() |
|
443 | |||
444 | 5 | public function setIsClassic($isClassic) |
|
448 | |||
449 | 3 | public function getType() |
|
453 | |||
454 | 2 | public function setType($type) |
|
458 | |||
459 | 3 | public function getAudienceConditions() |
|
463 | |||
464 | 2 | public function setAudienceConditions($audienceConditions) |
|
468 | |||
469 | public function getConfig() |
||
473 | |||
474 | public function setConfig($config) |
||
478 | |||
479 | 3 | public function getAllocationPolicy() |
|
483 | |||
484 | public function setAllocationPolicy($allocationPolicy) |
||
488 | |||
489 | 3 | public function getEarliest() |
|
493 | |||
494 | public function setEarliest($earliest) |
||
498 | |||
499 | 3 | public function getPageIds() |
|
503 | |||
504 | public function setPageIds($pageIds) |
||
508 | |||
509 | 3 | public function getLatest() |
|
513 | |||
514 | public function setLatest($latest) |
||
518 | |||
519 | 3 | public function getUrlTargeting() |
|
523 | |||
524 | public function setUrlTargeting($urlTargeting) |
||
528 | } |
||
529 | |||
530 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.