Correctness through simplicity
description
Transcript of Correctness through simplicity
Correctness through simplicityUlvi K. Guliyev
“…domain of dependable software engineering boils down less to money and more to ethics. Its about your duty as a software engineer to ensure that system is of as higher quality as possible.”
Prof. Joseph Kiniry (Software Development Group)
How do we think about computation?
Meet imperative Bob
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}if(burp != null)
_burps.Add(burp);}else{
Environment.Spit(foodItem, bob);}
}}foreach(var burp in _burps){
Environment.Release(burp);}
}
BranchLo
op
Side-effect
Jump
Loop
Side-effect
Loop
Branch
Branch
Branch
Branch
Branch Side-effect
Side-effect
∞ ∞
Meet accidental complexity
How do we change thinking
modality?
• We are computers• Technology is secondary• Intuition and ingenuity• Structured roadmap
Roadmap to dependable software
• Targeted at imperative programmers• Focus on reducing code complexity• Step by step discovery• Meant to alter the way we reason about
computation
Step 1. Procedural decomposition
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}if(burp != null)
_burps.Add(burp);}else
Environment.Spit(foodItem, bob);}
}foreach(var burp in _burps){
Environment.Release(burp);}
}
Operational
demarcation
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}if(burp != null)
burps.Add(burp);}else
Environment.Spit(foodItem, bob);}
}Burp();
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}
}
Step 2. Single responsibility
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}if(burp != null)
_burps.Add(burp);}else{
Environment.Spit(foodItem, bob);}
}}
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}
}
Responsibility demarcation
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp = ProcessFoodItem(foodItem, bob);if(burp != null)
_burps.Add(burp);else
Environment.Spit(foodItem, bob);}
}}Burp();
}
Burp ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {
Burp burp = null;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}return burp;
}
Step 3. Semantic regression
Code beacons
• Patterns in code• Sequences of imperative instructions• Describe how to compute and not computation itself• Denote hidden semantic intent
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = new List<Burp>();foreach(var dish in dishes){
foreach(var foodItem in dish.Items){if(foodItem.IsTasty(bob)){
Burp burp = ProcessFoodItem(foodItem, bob);if(burp != null)
_burps.Add(burp);else
Environment.Spit(foodItem, bob);}
}}Burp();
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}}
Beacon
Beacon
Beacon
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = ProcessFood(dishes, bob);Burp();
}
List<Burp> ProcessFood(List<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}}
Step 4. Controlled side-effects
void InsertNutritionalSubstance(List<Dish> dishes, ImperativeGeek bob){
_burps = ProcessFood(dishes, bob);Burp();
}
List<Burp> ProcessFood(List<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}}
Mutable type
Mutable
type
Mutable type
void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){
_burps = ProcessFood(dishes, bob);Burp();
}
IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}}
Step 6. Functional composition
void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){
_burps = ProcessFood(dishes, bob);Burp();
}
IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
void Burp(){
foreach(var burp in _burps){Environment.Release(burp);
}}
Non-compositional
void InsertNutritionalSubstance(IEnumerable<Dish> dishes, ImperativeGeek bob){
Burp(ProcessFood(dishes, bob));}
IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
void Burp(IEnumerable<Burp> burps){
foreach(var burp in burps){Environment.Release(burp);
}}
Composition
Step 7. Computational abstraction
IEnumerable<Burp> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
Burp ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {
Burp burp = null;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}return burp;
}
void Burp(IEnumerable<Burp> burps){
foreach(var burp in burps){Environment.Release(burp);
}}
Could be null
IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {
Burp burp = null;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;
}
void Burp(IEnumerable<<Maybe<Burp>> burps){
foreach(var burp in burps.Where(b => b.HasValue)){Environment.Release(burp);
}}
Step 8. Constrained state space
IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {
Burp burp = null;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;
}
∞ ∞
∞ ∞
IEnumerable<Maybe<Burp>> ProcessFood(IEnumerable<Dish> dishes, ImperativeGeek bob){
Contract.Requires(dishes.Any());Contract.Requires(bob.IsHungry);Contract.Ensures(bob.IsFull);
return dishes.SelectMany(d => d.Items) .Where(i => i.IsTasty(bob)) .Select(i => ProcessFoodItem(i, bob));
}
Maybe<Burp> ProcessFoodItem(FoodItem foodItem, ImperativeGeek bob) {
Contract.Requires(foodItem.ExpiryDate < DateTime.Now);Contract.Requires(foodItem.IsWarm);Contract.Requires(bob.IsHungry);
Burp burp = null;switch(foodItem.Kind){
case FoodKind.Yummy:bob.ConsumeItem(foodItem, out burp);break;
case FoodKind.Chewy:var timeout = TimeSpan.FromSeconds(10);bob.Chew(foodItem, timeout);break;
default:throw new Exception(“Yuk!”);
}return burp != null ? burp.ToMaybe() : Maybe<Burp>.Nothing;
}