srparish
Joined 17 years ago
Joined 17 years ago
The approach is slightly different then the article above describes. Instead it has each engineer go through calibration exercises until they can fairly accurately produce 5th and 95th confidence interval estimates. Then each engineer provides 5th and 95th confidence interval estimates for each item that needs to be worked on. Those confidence intervals are kept separate. You can then run a Monte Carlo simulation where each piece of work is weighted randomly assigned to each engineer that provided estimates for that particular item, and randomly picks a number based off their provided confidence interval estimate on how long it ends up taking them to complete the item for this particular simulation.
I was on a small team that used the above technique. We were in a large company trying to launch a new product, and given manufacturing lead time, and seasonality of the market demand, it was very important that we could provide a good estimate to the business when we could have the software portion of the MVP completed. The business provided us with what they thought the MVP features were, we further added in engineering tasks that weren't business facing, but needed to be completed. We confidence interval estimated those, and then also confidence interval estimated our personal vacation days, sick days, as well as a bucket of "unidentified work". The 80th percentile Monte Carlo simulation put us out a little more then a year. Our actual delivery was off by only a week from the Monte Carlo tp80; I don't remember in which direction, but it wasn't consequential to the business.
That's not been my experience. On a team I was on, even code from six months prior would sometimes be difficult to compile. They keep changing how GOPRIVATE works, or how modules work, or how vendoring works with modules.
hasThing := false
for _, v := range stuff {
if checkForThing(v) {
hasThing = true
break
}
}
if !hasThing {
return false
}
Java: if !stuff.stream().anyMatch(v -> checkForThing(v)) {
return false;
}
In the 2020s, loops are the new "goto", too much boiler-plate and ways to subtly be incorrect, much safer to use higher-level collection methods.+ gofmt feels way out of date. These days clang-format (c++), prettier (typescript), black (python), scalafmt (scala) take care of wrapping/unwrapping lines such as function definitions or function calls. They basically cover all formatting needs so you never have to manually format anything.
+ Scope of element in for-range loop isn't right, so capturing that scope in a lambda does the wrong thing with no warning.
+ Encourages use of indexes; which is error prone, most modern languages allow writing most code without needing indexes using map/filter/reduce or comprehensions.
+ No help from type-system for use of pointer without nil check.
+ Very easy to get nils in places one would hope to be able to prohibit them in. EG Using pointer as a poor man's unique_ptr<> means that I also get optional<> symantics (without the type checking) when I don't want or expect such. Also allows for aliasing when I don't want or expect such.
+ Difference between '=' and ':=' is silly, especially since ':=' can be used to reassign values. Even more frustrating that ':=' creates shadowing in nested scopes, so doesn't always do what one would expect it would do, such as accidentally creating a shadowed 'err' that doesn't get checked.
+ if/switch should be allowed to be expressions, allowing much safer single-expression initialization of variables, rather then requiring default initialization and mutation, which is much easier to get wrong.
- Changelog: https://changelog.com/podcast
- Functional Geekery: https://www.functionalgeekery.com/
- CppCast: http://cppcast.com/
1| https://www.scala-js.org/ 2| http://typelevel.org/cats/ 3| http://scalaz.github.io/scalaz/