public void Forecast_8_issues() { const int N_RESOURCES = 3; var issues = IssueRepository.Import().ToArray(); IEnumerable <Issue> Filter_issues(params string[] tags) => issues.Where(i => tags.All(t => i.Tags.Contains(t))); int[] Get_cycle_times_in_days(IEnumerable <Issue> issues) => issues.Select(x => x.CycleTime.Days).ToArray(); var frontend_feature_cts = Get_cycle_times_in_days(Filter_issues("frontend", "feature")); var backend_bug_cts = Get_cycle_times_in_days(Filter_issues("backend", "bug")); var backend_feature_cts = Get_cycle_times_in_days(Filter_issues("backend", "feature")); _testOutputHelper.WriteLine($"Events found: {frontend_feature_cts.Length}, {backend_bug_cts.Length}, {backend_feature_cts.Length}"); var sut = new SoftwareDeliverySimulation(); var simulationresult = sut.SimulateIssueDeliveryByResources(N_RESOURCES, frontend_feature_cts, frontend_feature_cts, frontend_feature_cts, backend_bug_cts, backend_feature_cts, backend_feature_cts, backend_feature_cts, backend_feature_cts ); var distribution = Statistics.Distribution(simulationresult); var deDE = new CultureInfo("de-DE"); foreach (var x in distribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } }
public void Forecast_based_on_all_issues() { var issues = IssueRepository.Import().ToArray(); var issueCycleTimes = issues.Select(x => x.CycleTime.Days).ToArray(); var distribution = Statistics.Distribution(issueCycleTimes); var deDE = new CultureInfo("de-DE"); foreach (var x in distribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } }
public void Forecast_10_stories_for_all_issue_forecasts() { DateTime START_DATE = new DateTime(2019, 11, 18); const int NUMBER_OF_STORIES = 10; var issues = IssueRepository.Import().ToArray(); var sut = new SoftwareDeliverySimulation(); var simulationresult = sut.SimulateStoryDeliveryBasedOnThroughput(START_DATE, NUMBER_OF_STORIES, issues); var distribution = Statistics.Distribution(simulationresult); var deDE = new CultureInfo("de-DE"); foreach (var x in distribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } }
public void Forecast_8_issues() { DateTime START_DATE = new DateTime(2019, 11, 18); const int NUMBER_OF_ISSUES = 8; var issues = IssueRepository.Import().ToArray(); var tp = issues.BusinessDayThroughputs(); _testOutputHelper.WriteLine($"TP sum: {tp.Sum()}"); var sut = new SoftwareDeliverySimulation(); var simulationresult = sut.SimulateIssueDeliveryBasedOnThroughput(START_DATE, NUMBER_OF_ISSUES, tp); var distribution = Statistics.Distribution(simulationresult); var deDE = new CultureInfo("de-DE"); foreach (var x in distribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } }
public void Forecast_10_stories_with_single_issue_forecast() { DateTime START_DATE = new DateTime(2019, 11, 18); const int NUMBER_OF_STORIES = 10; var issues = IssueRepository.Import().ToArray(); var issuesPerStory = issues.IssuesPerStory(); var sut = new SoftwareDeliverySimulation(); var issueSimulationresult = sut.SimulateIssuesDerivedFromStories( Enumerable.Range(1, NUMBER_OF_STORIES).Select(_ => issuesPerStory).ToArray() ); var issueDistribution = Statistics.Distribution(issueSimulationresult); _testOutputHelper.WriteLine("issues from stories forecast"); var deDE = new CultureInfo("de-DE"); foreach (var x in issueDistribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } _testOutputHelper.WriteLine("delivery forecast"); var number_of_issues = issueDistribution.First(x => x.percentile > 80.0).value; _testOutputHelper.WriteLine($"Number of issues selected: {number_of_issues}"); var tp = issues.BusinessDayThroughputs(); var deliverySimulationresult = sut.SimulateIssueDeliveryBasedOnThroughput(START_DATE, number_of_issues, tp); var distribution = Statistics.Distribution(deliverySimulationresult); foreach (var x in distribution.OrderBy(o => o.value)) { _testOutputHelper.WriteLine($"{x.value}\t{x.frequency}\t{x.probability.ToString("0.000", deDE)}\t{x.percentile.ToString("0.0", deDE)}"); } }
public void Run() { const int INITIAL_NUMBER_OF_ISSUES = 5; var sut = new Forecasting(); var issues = IssueRepository.Import().ToList(); var cts = issues.Select(x => x.CycleTime.Days).ToArray(); var ctsDistribution = Statistics.Distribution(cts); Export("CTs 2019-11-06.csv", ctsDistribution); var tps = issues.BusinessDayThroughputs(); var tpsDistribution = Statistics.Distribution(tps); Export("TPs 2019-11-06.csv", tpsDistribution); // initial forecast var numberOfIssues = INITIAL_NUMBER_OF_ISSUES; var fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 6), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 6), fc); // updating forecast after first issue got delivered issues.Add(new Issue(new DateTime(2019, 11, 6), new DateTime(2019, 11, 7), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 7), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 7), fc); issues.Add(new Issue(new DateTime(2019, 11, 7), new DateTime(2019, 11, 8), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 8), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 8), fc); issues.Add(new Issue(new DateTime(2019, 11, 6), new DateTime(2019, 11, 11), null, null, false)); numberOfIssues += -1 + 2; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 11), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 11), fc); issues.Add(new Issue(new DateTime(2019, 11, 11), new DateTime(2019, 11, 13), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 13), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 13), fc); issues.Add(new Issue(new DateTime(2019, 11, 8), new DateTime(2019, 11, 14), null, null, false)); numberOfIssues += -1 + 1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 14), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 14), fc); issues.Add(new Issue(new DateTime(2019, 11, 11), new DateTime(2019, 11, 15), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 15), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 15), fc); issues.Add(new Issue(new DateTime(2019, 11, 13), new DateTime(2019, 11, 18), null, null, false)); numberOfIssues += -1 + 2; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 18), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 18), fc); issues.Add(new Issue(new DateTime(2019, 11, 15), new DateTime(2019, 11, 19), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 19), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 19), fc); issues.Add(new Issue(new DateTime(2019, 11, 18), new DateTime(2019, 11, 20), null, null, false)); numberOfIssues += -1; fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 20), numberOfIssues, issues.ToArray()); Export(new DateTime(2019, 11, 20), fc); issues.Add(new Issue(new DateTime(2019, 11, 18), new DateTime(2019, 11, 21), null, null, false)); numberOfIssues += -1; Assert.Equal(0, numberOfIssues); // rear mirror wisdom fc = sut.WhenWillTheIssuesBeDone(new DateTime(2019, 11, 6), INITIAL_NUMBER_OF_ISSUES + 5, issues.ToArray()); File.Move("2019-11-06.csv", "2019-11-06-v1.csv", true); Export(new DateTime(2019, 11, 6), fc); File.Move("2019-11-06.csv", "2019-11-06-v2.csv", true); cts = issues.Select(x => x.CycleTime.Days).ToArray(); ctsDistribution = Statistics.Distribution(cts); Export("CTs 2019-11-21.csv", ctsDistribution); tps = issues.BusinessDayThroughputs(); tpsDistribution = Statistics.Distribution(tps); Export("TPs 2019-11-21.csv", tpsDistribution); }