Last active
December 29, 2019 23:19
-
-
Save entrofi/14430eb7c4a0e73ffde4e70dc7244dbd to your computer and use it in GitHub Desktop.
Github’s Scientist as a helper to do large refactorings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<dependency> | |
<groupId>com.github.rawls238</groupId> | |
<artifactId>Scientist4JCore</artifactId> | |
<version>${Scientist4JCore.version}</version> | |
</dependency> | |
<!-- Scientist4JCore.version = 0.6 for this example --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public String greet(String name) { | |
initReporter(); | |
Supplier<String> oldSupplier = () -> this.oldService.greet(name); | |
Supplier<String> newSupplier = () -> this.newService.greet(name); | |
String greetingMessage = null; | |
try { | |
greetingMessage = this.serviceExperiment.run(oldSupplier, newSupplier); | |
} catch (Exception e) { | |
LOGGER.error("Exception occurred while running the experiment", e); | |
} | |
reportAndStop(); | |
return greetingMessage; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.entrofi.examples.refactoring.scientist.service; | |
import io.dropwizard.metrics5.ConsoleReporter; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.concurrent.TimeUnit; | |
import java.util.function.Supplier; | |
public class ExperimentingGreeterService implements GreeterService { | |
private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentingGreeterService.class); | |
private GreeterService oldService; | |
private GreeterService newService; | |
private GreeterServiceExperiment serviceExperiment; | |
private ConsoleReporter reporter; | |
public ExperimentingGreeterService() { | |
this.oldService = new OldGreeterService(); | |
this.newService = new NewGreeterService(); | |
this.serviceExperiment = new GreeterServiceExperiment(); | |
} | |
@Override | |
public String greet(String name) { | |
initReporter(); | |
Supplier<String> oldSupplier = () -> this.oldService.greet(name); | |
Supplier<String> newSupplier = () -> this.newService.greet(name); | |
String greetingMessage = null; | |
try { | |
greetingMessage = this.serviceExperiment.run(oldSupplier, newSupplier); | |
} catch (Exception e) { | |
LOGGER.error("Exception occurred while running the experiment", e); | |
} | |
reportAndStop(); | |
return greetingMessage; | |
} | |
public GreeterServiceExperiment getServiceExperiment() { | |
return serviceExperiment; | |
} | |
private void initReporter() { | |
reporter = ConsoleReporter | |
.forRegistry( | |
this.getServiceExperiment().getMetrics(null) | |
) | |
.convertRatesTo(TimeUnit.SECONDS) | |
.convertDurationsTo(TimeUnit.MILLISECONDS) | |
.build(); | |
reporter.start(1, TimeUnit.MILLISECONDS); | |
} | |
private void reportAndStop() { | |
reporter.report(); | |
reporter.stop(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io.dropwizard.metrics5.ConsoleReporter; | |
import org.junit.Before; | |
import org.junit.Test; | |
import java.util.concurrent.TimeUnit; | |
public class ExperimentingGreeterServiceTest { | |
private ConsoleReporter reporter; | |
private ExperimentingGreeterService service; | |
@Before | |
public void setup() { | |
service = new ExperimentingGreeterService(); | |
reporter = ConsoleReporter | |
.forRegistry( | |
service.getServiceExperiment().getMetrics(null) | |
) | |
.convertRatesTo(TimeUnit.SECONDS) | |
.convertDurationsTo(TimeUnit.MILLISECONDS) | |
.build(); | |
reporter.start(1, TimeUnit.SECONDS); | |
} | |
@Test | |
public void greet() { | |
for( int i = 0; i < 10; i++) { | |
service.greet("Comak"); | |
} | |
reporter.report(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.entrofi.examples.refactoring.scientist.service.GreeterService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.PathVariable; | |
import org.springframework.web.bind.annotation.RestController; | |
@RestController | |
public class GreeterController { | |
@Autowired | |
private GreeterService greeterService; | |
@GetMapping("/greet/{name}") | |
public String greet(@PathVariable("name") String name) { | |
return greeterService.greet(name); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface GreeterService { | |
String greet(String name); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.github.rawls238.scientist4j.Experiment; | |
import com.github.rawls238.scientist4j.Result; | |
import io.dropwizard.metrics5.Gauge; | |
import io.dropwizard.metrics5.MetricName; | |
import io.dropwizard.metrics5.MetricRegistry; | |
public class GreeterServiceExperiment extends Experiment<String> { | |
private Result<String> result; | |
@Override | |
protected void publish(Result<String> result) { | |
this.result = result; | |
MetricRegistry metricRegistry = this.getMetrics(null); | |
MetricName greetingGauge = MetricName.build(GreeterServiceExperiment.class.getCanonicalName(), "greeting"); | |
if (metricRegistry.getMetrics().get(greetingGauge) == null) { | |
Gauge<String> gauge = this::getResultGaugeValue; | |
metricRegistry.register(MetricRegistry.name(greetingGauge.getKey()), gauge); | |
} | |
} | |
private String getResultGaugeValue() { | |
if (getResult() != null && getResult().getCandidate().isPresent()) { | |
if (Boolean.FALSE.equals(getResult().getMatch().get())) { | |
return getResult().getCandidate().get().getValue() + " does not match " + getResult().getControl().getValue(); | |
} else { | |
return getResult().getCandidate().get().getValue() + " matches " + getResult().getControl().getValue(); | |
} | |
} | |
return "Nothing to say!"; | |
} | |
private Result<String> getResult() { | |
return this.result; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class NewGreeterService implements GreeterService { | |
@Override | |
public String greet(String name) { | |
String[] greetings = {"Hallo ", "Hello "}; | |
int choice = new Random().nextInt(2); | |
return greetings[choice] + name; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.entrofi.examples.refactoring.scientist.service.OldGreeterService; | |
import net.entrofi.examples.refactoring.scientist.service.GreeterService; | |
import org.springframework.beans.factory.config.ConfigurableBeanFactory; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.Scope; | |
@Configuration | |
public class ServiceConfigurer { | |
@Bean | |
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) | |
public GreeterService greeterService() { | |
GreeterService greeterService = new OldGreeterService(); | |
return greeterService; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class OldGreeterService implements GreeterService { | |
@Override | |
public String greet(String name) { | |
return "Hello " + name; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=========================================================== | |
-- Gauges ---------------------------------------------------------------------- | |
net.entrofi.examples.refactoring.scientist.service.GreeterServiceExperiment.greeting | |
value = Hallo hasan does not match Hello hasan | |
-- Counters -------------------------------------------------------------------- | |
scientist.Experiment.candidate.exception | |
count = 0 | |
scientist.Experiment.mismatch | |
count = 1 | |
scientist.Experiment.total | |
count = 4 | |
-- Timers ---------------------------------------------------------------------- | |
scientist.Experiment.candidate | |
count = 4 | |
sum = 12347191609 | |
mean rate = 0.06 calls/second | |
1-minute rate = 0.04 calls/second | |
5-minute rate = 0.01 calls/second | |
15-minute rate = 0.00 calls/second | |
min = 0.01 milliseconds | |
max = 6560.61 milliseconds | |
mean = 3122.60 milliseconds | |
stddev = 3035.04 milliseconds | |
median = 5786.55 milliseconds | |
75% <= 5786.55 milliseconds | |
95% <= 6560.61 milliseconds | |
98% <= 6560.61 milliseconds | |
99% <= 6560.61 milliseconds | |
99.9% <= 6560.61 milliseconds | |
scientist.Experiment.control | |
count = 4 | |
sum = 44084 | |
mean rate = 0.06 calls/second | |
1-minute rate = 0.04 calls/second | |
5-minute rate = 0.01 calls/second | |
15-minute rate = 0.00 calls/second | |
min = 0.00 milliseconds | |
max = 0.03 milliseconds | |
mean = 0.01 milliseconds | |
stddev = 0.01 milliseconds | |
median = 0.00 milliseconds | |
75% <= 0.00 milliseconds | |
95% <= 0.03 milliseconds | |
98% <= 0.03 milliseconds | |
99% <= 0.03 milliseconds | |
99.9% <= 0.03 milliseconds |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.entrofi.examples.refactoring.scientist.service.ExperimentingGreeterService; | |
import net.entrofi.examples.refactoring.scientist.service.GreeterService; | |
import org.springframework.beans.factory.config.ConfigurableBeanFactory; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.Scope; | |
@Configuration | |
public class ServiceConfigurer { | |
@Bean | |
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) | |
public GreeterService greeterService() { | |
ExperimentingGreeterService greeterService = new ExperimentingGreeterService(); | |
return greeterService; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment