Skip to content

Instantly share code, notes, and snippets.

@entrofi
Last active December 29, 2019 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save entrofi/14430eb7c4a0e73ffde4e70dc7244dbd to your computer and use it in GitHub Desktop.
Save entrofi/14430eb7c4a0e73ffde4e70dc7244dbd to your computer and use it in GitHub Desktop.
Github’s Scientist as a helper to do large refactorings
<dependency>
<groupId>com.github.rawls238</groupId>
<artifactId>Scientist4JCore</artifactId>
<version>${Scientist4JCore.version}</version>
</dependency>
<!-- Scientist4JCore.version = 0.6 for this example -->
@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;
}
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();
}
}
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();
}
}
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);
}
}
public interface GreeterService {
String greet(String name);
}
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;
}
}
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;
}
}
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;
}
}
public class OldGreeterService implements GreeterService {
@Override
public String greet(String name) {
return "Hello " + name;
}
}
===========================================================
-- 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
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