Upload
hoholoho
View
387
Download
2
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
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;
}