This document provides guidance on framework design. It discusses how organizational structure and culture can impact a product. Frameworks should manage dependencies and balance new features with maintaining compatibility. Duplication and unfinished features should be avoided. APIs should be designed based on code samples for key scenarios before defining object models. Simplicity is important and thorough testing and measurement is needed. Framework engineering best practices from Microsoft, Cwalina, and Schmidt are referenced.
14. DO understand how organizational structure,
culture, and decision making processes impa
ct your product.
O
15. If you have 4 groups working on a compiler,
you’ll get a 4-pass compiler.
16. If you have four groups working on a compiler,
you’ll get a 4-pass compiler.
Organization Software
Structure Structure
17. • Define the business mission
1
• Learn the business process from business owners
2
• Re-engineer these process to fit the mission
3
• Structure the IT organization to support the reengine
4 ered business processes.
29. Peanut Butter Skyscrapers
Focus: features Focus: scenarios
Results: stability, Results: Excitement,
incremental breakthroughs, but
improvements, not beware of leaving
great end-to-end
end-to- existing customers
P
scenarios behind
33. A Component is a set of types that ship and evolve
as a unit.
Componentization is a process of organizing types into components, w
ith explicitly designed and controlled dependencies between compon
ents.
ents
NOTE: Componentization is different from assembly factoring (i.e. an a
ssembly might have more than one component)
A
34. API Dependency: Component A has an API dependency on compon
ent B, if a type in B shows in the publicly accessible (public or prote
cted) API surface of a type in A. This includes:
Base types and implemented interfaces
Generic parameter constraints
Return types and parameters of members
Applied attributes
Nested types
Implementation Dependency: If a type in A uses a type in B in its im
plementation.
Hard Dependencies (required to run)
Soft Dependencies (optional)
Circular Dependency occurs when component A depends on comp
onent B and component B depends on component A (even indirect
ly).
Note: Two (or more) components with a circular API dependencies can b
e considered a single component for all practical purposes.
A
35. Layering is a process of organizing components in layers and enforcing dependency
rules between components in these layers.
A
36. Types in a component can freely depend on each other
Cross-component dependencies must be carefully controlled
A component can freely take dependencies on components in a lower layer
A component must not have hard dependencies on components in higher layers.
A component should avoid soft dependencies on components in higher layers.
Dependencies between components of the same layer must be carefully managed. [NOT
E: we have an approval process for these]
In general it’s good to minimize dependencies, if it does not create to much duplic
ation (bloat)
A
40. Very little policy (behavior design decisions)
Stable design
Commonly appear in publicly accessible APIs
Almost impossible to evolve/change design; any design changes
have huge breaking change impact on other APIs
Example: Int32, String
A
41. Interfaces, abstract classes, some concrete classes wi
th extensive virtual surface.
Similar to Primitives (show in APIs), but usually have
more policy (though less than libraries)
The hardest types to design right
With the exception on a few historically well understo
od abstractions (lists, streams, etc.), abstractions with
more than 2-3 members are rarely successful.
Difficult to evolve
Glue between parts of the framework
Through polymorphism
Very useful for decoupling components
Examples: Stream, IEnumerable<T>
A
42. Perform operations on primitives and abstractions (or the system)
Almost never passed around
Change often as frameworks evolve
XmlDocument (Fx 1.0 – XML DOM)
XPathDocument (Fx 2.0 - XPath)
XDocument (Fx 3.5 – Linq to XML)
Relatively easy to evolve (if designed and used properly); they can be simply
replaced.
Examples: XmlDocument, EventLog, SerialPort
A
43. Rich APIs with lots of features, thus with lots of dependencies
Great usability, poor evolvability
E.g. Object.GetType() – Every object has very easy access to its type, but also
every object depends on Reflection
Good for higher level components, not for the core of a platform
NOTE: “Component” is an overloaded term. In this context it does not have a
nything to do with “componentization.” Unfortunately, COD is already an esta
blished term.
A
44. A.K.A. “Handle based design” (functional)
Great evolvability, poor usability (sometimes)
Low level sable primitives + high level reusable components with limited dep
endencies other than to the primitives
E.g. Type.GetType(object) – works, but not as convenient as Object.GetType
A
45. Members with “heavy” dependencies can be extension metho
ds for primitives in a separate component.
This is essentially functional programming
// low level assembly with no dependency on globalization
namespace System {
public struct Decimal {
public string ToString(); // culture independent
}
}
// higher level assembly
namespace System {
public static class DecimalFormatter {
// decimal point character is culture sensitive
public static string ToString(this Decimal d, string format);
}
}
Note: Same namespace makes the API easy to use A
47. Cross-Version Compatibility: code written for a version of a redist wor
ks on a different version of the same redist.
Cross-Redist Compatibility: code written for a redist works on a differ
ent redist.
Backward Compatibility: code written for a version of a redist works o
n a newer version of the same redist.
Forward Compatibility: code written for a version of a redist works on
a previous version of the same redist.
A
48. Binary Compatibility: a binary runs on a different
version or a different redist than what it was buil
d for without recompilation.
Source Compatibility: source code compiling on
a version of a redist can be recompiled without c
hanges on a different version or a different redist.
API Compatibility: Stronger than source. Weaker
than binary. Source compatibility allows for some
changes in APIs (e.g. covariant changes to input p
arameters). API Compatibility does not.
A
49. Define what’s a “breaking change”
This definition depends on the objective
E.g. Enable portable code between Silverlight and .
NET Framework
E.g. Enable cross-version portability?
For example, Silverlight interfaces cannot have l
ess members than .NET interfaces, but concrete
types can.
A
51. AVOID duplication and overlap.
Problem Space Show and Tell
PLoP – Capable, Productive and Satisfied Patterns for Productivity
A
http://hillside.net/plop/plop98/final_submissions/P54.pdf
52. When the new technology is “10x better”
Make sure you understand the impact on the ec
osystem
What would happen if the BCL team added a new S
tring?
What’s the migration path for code using the ol
d API?
A
56. static void Main(string[] args)
{
StreamReader sr = File.OpenText(quot;MyFile.txtquot;);
string s = sr.ReadLine();
while (s != null)
{
s = sr.ReadLine();
Console.WriteLine(s);
}
}
57. static void Main(string[] args)
{
foreach (string s in File.ReadAllLines(quot;MyFiles.textquot;))
{
Console.WriteLine(s);
}
}
67. Performance Goals
Baseline: What do is the best my API could do?
Measure delta from the baseline
Threat Models
Threat: What is the worst that my component co
uld do?
Mitigate the threats
Same for many other qualities you want your f
ramework to have
D
71. Functional Specification
Developer Design Specification
Test Plan
Threat Model
API review
Architectural Review
Dependency Management
Static Analysis
Code Coverage
Testing (Unit and Integration Tests)
0 Bugs
Performance
V
74. Initiatives that are hard to do in regular milestones
Large productivity and efficiency improvements
Infrastructure changes
For example, a new source control system
Refactoring of fragile subsystems
Internal implementation documentation
Bugs backlog
V
75. DO understand how organizational structure, culture, and decision making proc
esses impact your product.
AVOID peanut-butter in Scenario Based Application.
DO manage your dependencies.
DO balance advances with compatibility.
AVOID duplication and overlap.
DO design APIs by first writing code samples for the main scenarios and then d
efining the object model to support the code samples.
DO treat simplicity as a feature.
DO measure, measure, and measure!
AVOID integrating unfinished features.
DO pay your debt.
77. Douglas C. Schmidt (PLoP Editor, POSA 2, 4 Writter)
JAWS: An Application Framework for High Performance Web System
http://citeseer.ist.psu.edu/81775.html (En)
http://www.devpia.com/net2/EvaCast/Lecture/?cu=view&r=11 (Kr)
Ralph Johnson (GoF , Design Patterns)
Evolving Frameworks
http://st-www.cs.uiuc.edu/users/droberts/evolve.html (En)
http://arload.wordpress.com/2008/09/15/evolvingframeworks/ (Kr)