domingo 1 de marzo de 2009

Sw is engineering of a higher kind

I´m copying an author I admire for the title of this.

LIE 1 (bad mapping): Writing sw is implementing a paper design
Writing sw is PURE and ONLY design: implementation is what all our tools do, we do not implement anything directly! (this comes from Uncle Bob)
Programmer vs Developer: writing throwaway code is akin to doing pretty pictures of imagined buildings (vs designing and building them)
Sw deals with abstractions using well defined logical constructs. By following the rules of logic we can assure ourselves that a general purpose infrastructure (namely a Universal Turing Machine pseudo implementation or, if you are a "real-world" no-nonsense guy, a computer with an OS) can execute a implementation of that design (the final product of the code we wrote). The implementation is written by compilers, linkers ... and is used with the help of the Hw, OS, and even VM.

LIE 2 (convenient exploitation): Developing sw cannot be engineering
If the previous where true then, by logic engineering is a logical impossibility. If sw dev cannot be engineering THEN nothing can ...
Let's dissolve all the objections usually presented (again and again). Another story (extremely interesting) is if we want/need sw engineering in general ...

- Law, regulation, rights and obligations
We will say this is not an engineered product if you let us say it is not fit for anything ...
We will say this is not engineering so we can do things any way we want (possibly can)
We will call you are junior programmer and give you an H1B visa and some peanuts for your engineering (but I´ll have to manage you as I have an MBA ...). I just hope this crisis teaches us something about the 'virtual' lies we create ...

- Profession, Art, Experimentation or prototyping
Prof: But I like x so it must be either illegal, unhealthy or a hobby
Art: but I just want to do as I please, pretty please ... Ditto
Prot: I have no clue about this but let me try

Sw can be used and applied to as much areas as engineering, but we have lots of engineer types and only a few common ideas about all computable things ...

- Process
Process is a distillation of practice: traditionally sw process has been postulated the other way around. We started to get globally vocal against this in the last decade (extreme, light-weight, adaptive, evolutionary ...).
You cannot use the same process to build a bridge and to build a car: why do you expect the same process to work for a web site and an office suite (other than some very high level vagaries worthy of a con man)?

Historically getting to engineering follows a path: ingenuity, artist, artisan, guild, ...

LIE 3 (libertarian mind-body delusion): But sw is not real, no physical things ...
See point 1: sw development is design, repeat until fully understood.
We can, to a point, liberate ourselves from implementation machinery (compilers, VMs, interpreters, Operating systems, networking sw : infrastructure) that do the dirty implementation job ... And, like all design, we can pile up abstractions, with a cost.

The 1M monkeys typing idea (we are getting close to this ...): A monkey can do a mark on a bar and it will hold the whole wikipedia codified as a very long fraction. So just one monkey (after a few tries) can generate the distilled accumulated knowledge of the whole species ... Like, you know, there is no spoon (we wish).
Copying sw is as inexpensive as copying any other 'paper' plans, the 'theft' is done when you execute it ...
Car builders do not sell to end-users robot factories that allow you to build car designs (too expensive, bad business), but computing sells you the machines and base sw to execute, create and copy sw designs. That´s the computing revolution ...

And engineering of a higher kind is the one you get when you use your engineered tools to engineer betters tools to design and build other 'accepted' engineered products. We seem a bit lost now, but we are doing our job!

lunes 9 de junio de 2008

Hw vs Sw

Men and women, hawks and doves ...
Hw and Sw are like the ying and yang of the information revolution. Of course, all dualities hide a continuum and literally one cannot live without the other.
People think they understand hw (maybe they do), but I'm pretty sure they do not understand sw (I doubt I do either).
This entry tries to enumerate differences and synergies among both.


Sw predates Hw (in the sense of sw-running hw). Seems perplexing but it is true. It took some time to realize the minimal hw needed for sw to run on it. It is great that (finite) Turing-like hw is enough to run any computable sw.


Hw employs a minimal fragment of the people sw employs.
Hw produces a millionth of the different products sw produces.
Hw evolution has been consistently macro-predicted, the latest models of sw release take fixed points in time with no sure prediction of achieved functionality (but we get some).
Hw mistakes can destroy manufacturers. Sw mistakes have to be labeled as features.
A mistake in a hw piece requires its replacement. A mistake in a sw piece requires a patch write.
We have 2 centuries of experience with mass-produced goods, but only a few decades of sw quality evaluation.
A faulty Hw piece is easy to identify. A faulty Sw piece can take millions of people years to identify.
It is extremely expensive to produce 1 new piece of hw, a mass-market is needed. It is relatively inexpensive to produce a non-complex piece of sw, but it is extremely expensive to grow from it.
Hw duplication is expensive. Sw duplication is almost free.
Hw is Sw that has solidified too early. Sw is Hw that has not been fully debugged yet.
There is not such thing as a bug-free (non-trivial) sw.
Hw platforms change slowly. New sw platforms are developed every few years. (Understand platform as ecosystem, integration ...)
MS is a closed sw platform builder that owns an open hw platform. Apple is a closed hw platform builder that owns a (semi-)open sw platform. Linux is an open sw infrastructure to run sw on multiple hw platforms. (see open/closed, here open can be semi-open)
You can build Hw by componentization, duplication ... You can try to build sw by piling up stuff, but you usually just get a big mess.
Current Hw is no longer execution-predictable. Current sw no longer fits into one's head.
You cannot easily start again with a Hw architecture. You'd do better redesigning your sw architecture (and emulating the old one if needed).
The barriers to entry into Hw are colossal. A monkey with a PC could create good sw.
You can educate a Hw engineer predictably. Education alone cannot produce good Sw engineers.
A Hw engineer can plan his career. A Sw engineer considers himself lucky if he can plan his vacation.
When hw is badly done, only publicity can save you. When sw is badly done, you can get away with murder.
Good Hw guys usually were good mechanical tinkering children. Good Sw guys usually were insufferable philosophical kids.
Hw is provided as is but has full warranty. Sw is tailored to death, but has no warranty whatsoever.
Hw guys are to surgeons as Sw guys are to psychologists.

...

sábado 7 de junio de 2008

Design Patterns

No blog about design can avoid mentioning GoF's book. It took the world by storm in the middle 90s and little by little it percolated to mainstream programming. After it there are JEE patterns, distributed patterns, enterprise patterns ... you name it.
Gof's comes from the Smalltalk tradition and shows how to add flexibility to class-based OO languages like C++ and Java. Gof's defines a common vocabulary and typical design solutions for some problems (based on the architectural work of Alexander). In this century critics have reacted to this, despising (with reason) those who use patterns like recipes (see Kerivesky's work for a reasonable alternative) and languages who need these patterns as "broken" (partly true). Newer languages based on the class-based OO tradition have tried to simplify or directly implement as idioms these patterns. Gof's is a book EVERY designer should read and understand, anyway.

I'll enumerate (with some notes) all Gof patterns (and some more here). I'll try to show some Scala implementation of these patterns as a personal exercise. UML 2 tries to simplify pattern representation (aiding to represent other high-level multiclass 'packages'). There is a nice (if slighty mocking) pseudo elements table relating them (worth printing to despise unknowing 'hackers').


Creational
These are patterns that try to simplify and generalize object creation strategies.
Singleton; Factory Method; Abstract Factory; Builder; Prototype

Structural
These help building common object structures.
Adapter; Decorator; Façade; Bridge; Composite; Flyweight; Proxy

Behavioral Patterns
These help building common collaboration patterns.
Chain of Responsibility; Visitor; Observer; Iterator; Mediator;State; Command; Mememto; Strategy

And, finally Gof includes a pseudojoke to help remember that no 'static' language is sacred and that scripting is usually needed: Interpreter.

Great book, (not the last word) but a common ground for OO developers.



Also check: JEE patterns, enterprise patterns, analysis patterns, ...

Davis' 201 principles of software development

This is a rewriting of Alan Davis' excellent 201 principles of sw dev list of principles. Some could be in several places (but I imposed myself to only show them once ...).
Some abilities can only be acquired by doing; Others will not be acquired early enough (if ever) unless good formal education is received early. Even others cannot be acquired (or only with too much effort) by some people.

Not all are valid now and you may not agree with all of them.

Outdated
CASE Tools Are Expensive (economically)
Be Optimistic About Hardware Evolution (current hw evolution requires mastery of concurrency).


Quality
Quality Is #1; Quality Is in the Eyes of the Beholder; Don't Try to Retrofit Quality; Productivity and Quality Are Inseparable; High-Quality Software Is Possible; Poor Reliability Is Worse Than Poor Efficiency
Comments
Avoid Broken windows; Avoid it works 'somehow'

People
Give Products to Customers Early; Communicate with Customers/Users; Align Incentives for Developer and Customer; Align Reputation With Organization; Follow the Lemmings With Care; Give Software Tools to Good Engineers;
Comments
Only those Doing can tell how, others can tell what.

Building (and Prototyping)
Grow Systems Incrementally; Change During Development Is Inevitable; If Possible, Buy Instead of Build; Build Software So That It Needs a Short Users' Manual; Every Complex Problem Has a Solution; Different Languages for Different Phases; Technique Before Tools; Use Tools, but Be Realistic; CASE Tools Are Expensive (in the process sense); "Know-When" Is as Important as Know-How; Stop When You Achieve Your Goal; Plan to Throw One Away; Build the Right Kind of Prototype; Build the Right Features into a Prototype; Build Throwaway Prototypes Quickly; The More Seen, the More Needed

Comments
If you PLAN to throw one away, you WILL throw two!



Documentation (and communication)
Record Your Assumptions; Use Documentation Standards; Every Document Needs a Glossary; Every Software Document Needs an Index; Use the Same Name for the Same Concept;
Comments
If you plan to document late you won't, or worse; Unsynch'ed docs are worse than no docs (except for saving face);
If you cannot do docs you are NOT a good developer: CANNOT deal with multiple languages, NO abstraction capability; NO design; CANNOT communicate


Education
Know Formal Methods; Don't Ignore Technology; Research-Then-Transfer Doesn't Work; Take Responsibility
Comments
If you are not educated, you will AT BEST reinvent all wheels


Requirements
Poor Requirements Yield Poor Cost Estimates; Determine the Problem Before Writing Requirements; Determine the Requirements Now; Fix Requirements Specification Errors Now; Prototypes Reduce Risk in Selecting User Interfaces; Record Why Requirements Were Included; Identify Subsets; Review the Requirements; Avoid Design in Requirements; Use the Right Techniques; Use Multiple Views of Requirements; Organize Requirements Sensibly; Prioritize Requirements; Write Concisely; Separately Number Every Requirement; Reduce Ambiguity in Requirements; Augment, Never Replace, Natural Language ; Write Natural Language Before a More Formal Model; Keep the Requirements Specification Readable; Specify Reliability Specifically; Specify When Environment Violates "Acceptable" Behavior; Self-Destruct TBDs; Store Requirements in a Database
Comments
Do not do GUI without fast prototyping tools, else stay with TUI! (No tools, no GUI)
Whys and assumptions provide metaknowledge

Design
Transition from Requirements to Design Is Not Easy; Trace Design to Requirements; Evaluate Alternatives; Design Without Documentation Is Not Design; Encapsulate; Don't Reinvent the Wheel; Keep It Simple; Avoid Numerous Special Cases; Minimize Intellectual Distance; Keep Design Under Intellectual Control; Maintain Conceptual Integrity; Conceptual Errors Are More Significant Than Syntactic Errors; Use Coupling and Cohesion; Design for Change; Design for Maintenance; Design for Errors; Build Generality into Software; Build Flexibility into Software; Use Efficient Algorithms; Module Specifications Provide All the Information the User Needs and Nothing More; Design Is Multidimensional; Great Designs Come from Great Designers; Know Your Application; You Can Reuse Without a Big Investment; "Garbage In, Garbage oUt" Is Incorrect; Software Reliability Can Be Achieved Through Redundancy



Comments
"Garbage In, Garbage oUt" Is Incorrect (?): design garbage rejection (checks, PbC ...) The world is a mess, build a garden.
Do not outclever yourself; Be humble (but ask for a raise!)
Transition from Requirements to Design Is Not Easy : The whole industry is taking more than 20 years to learn this: OO, XP, Agile, Declarative, Iterative, Incremental ... But then it goes against the pay structure ... So real designers disappear
No evaluation of alternatives means a lemming is following a script
KISS: If we wanted complex, we would be doing it like always (without sw help)
Design for change: YAGNI, for you ...
Build Generality into Software: grow it!
Use Efficient Algorithms: Oh, but I would need education for that ...
The interface (in all senses) is the sw (to non-builders)

Coding
Avoid Tricks; Avoid Global Variables; Write to Read Top-Down; Avoid Side-Effects; Use Meaningful Names (for meaningful stuff); Write Programs for People First; Use Optimal Data Structures; Get It Right Before You Make It Faster; Comment Before You Finalize Your Code; Document Before You Start Coding; Hand-Execute Every Component; Inspect Code; You Can Use Unstructured Languages; Structured Code Is Not Necessarily Good Code; Don't Nest Too Deep; Use Appropriate Languages; Programming Language Is Not an Excuse; Language Knowledge Is Not So Important; Format Your Programs; Don't Code Too Soon


Comments
Write Programs for People First: This is the most important principle for coders (but choose your readers !)
Use Optimal Data Structures: requires education
Get It Right Before You Make It Faster: premature optimization
You Can Use Unstructured Languages: or untyped, or hacked (just be knowledgeable of the trade offs)
Don't Code Too Soon: true, but (for sweatshops) neither too late!
Removing lines of code is Good.


Testing
Trace Tests to Requirements; Plan Tests Long Before It Is Time to Test; Don't Test Your Own Software; Don't Write Your Own Test Plans; Testing Exposes Presence of Flaws; Though Copious Errors Guarantee Worthlessness, Zero Errors Says Nothing About the Value of Software; A Successful Test Finds an Error; Half the Errors Found in 15 Percent of Modules; Use Black-Box and White-Box Testing; A Test Case Includes Expected Results; Test Invalid Inputs; Always Stress Test; The Big Bang Theory Does Not Apply; Use McCabe Complexity Measure; Use Effective Test Completion Measures; Achieve Effective Test Coverage; Don't Integrate Before Unit Testing; Instrument Your Software; Analyze Causes for Errors; Don't Take Errors Personally

Comments
Nowadays, no unit testing means component coding is unfinished
Untested sw is worth less than zero: some people get away with making users the testers ...
You only learn from mistakes (if you ever learn).


Management
Good Management Is More Important Than Good Technology; Use Appropriate Solutions; Don't Believe Everything You Read; Understand the Customers' Priorities; People Are the Key to Success; A Few Good People Are Better Than Many Less Skilled; Listen to Your People; Trust Your People; Expect Excellence (and be a model); Communication Skills Are Essential; Carry the Water; People Are Motivated by Different Things; Keep the Office Quiet; People and Time Are Not Interchangeable; There Are Huge Differences Among Software Engineers; You Can Optimize Whatever You Want; Collect Data Unobtrusively; Cost Per Line of Code Is Not Useful; There Is No Perfect Way to Measure Productivity; Tailor Cost Estimation Methods ; Don't Set Unrealistic Deadlines; Avoid the Impossible; Know Before You Count; Collect Productivity Data; Don't Forget Team Productivity ; LOC/PM Independent of Language; Believe the Schedule; A Precision-Crafted Cost Estimate Is Not Foolproof; Reassess Schedules Regularly; Minor Underestimates Are Not Always Bad; Allocate Appropriate Resources; Plan a Project in Detail; Keep Your Plan Up-to-Date; Avoid Standing Waves; Know the Top 10 Risks; Understand Risks Up Front; Use an Appropriate Process Model; The Method Won't Save You; No Secrets for Miraculous Productivity Increases; Know What Progress Means; Manage by Variance; Don't Overstrain Your Hardware; Be Pessimistic About Software Evolution; The Thought That Disaster Is Impossible Often Leads to Disaster; Do a Project Postmortem

Comments
Don't Believe Everything You Read: This is the most important principle for managers
People trumps process, technology and rules
Use Appropriate Solutions: use proportional force
There Are Huge Differences Among Software Engineers: but it is in the interest of many (bad ones, the paying structure, friends) to hide this; but please, at least, remove the negative producers.
You Can Optimize Whatever You Want: but optimizing something may mean not optimizing something else.
Collect Data Unobtrusively: do not try to turn everybody into bean counters.
Cost Per Line of Code Is Not Useful: If you do not agree, then YOU are not useful.
Don't Set Unrealistic Deadlines: they are not deadlines, they are just ignored (maybe silently).
Know Before You Count: apples and oranges may not add up.
Nothing is foolproof: fools are the most intelligent agents of entropy in the Universe.
Be Pessimistic About Evolution: (surprise) entropy wins in the end.
The Method Won't Save You: Only people save (amen).
Manage by Variance: be a change detector and presenter.
(non natural) Disaster: requires multiple failures in a chain: if it happens, MANY things where done wrong. Some people really believe things sort out by themselves!


Product Assurance
Product Assurance Is Not a Luxury; Establish SCM Procedures Early; Adapt SCM to Software Process; Organize SCM to Be Independent of Project
Management; Rotate People Through Product Assurance; Give Every Intermediate Product a Name and Version; Control Baselines; Save Everything; Keep Track of Every Change; Don't Bypass Change Control; Rank and Schedule Change Requests; Use Validation and Verification (V&V) on Large
Developments


Evolution
Software Will Continue to Change; Software's Entropy Increases; If It Ain't Broke, Don't Fix It; Fix Problems, Not Symptoms; Change Requirements First; Prerelease Errors Yield Postrelease Errors; The Older a Program, the More Difficult It Is to Maintain; Language Affects Maintainability; Sometimes It Is Better to Start Over; Renovate the Worst First; Maintenance Causes More Errors Than Development; Regression Test After Every Change; Belief That a Change Is Easy Makes It Likely It Will Be Made Incorrectly; Structuring Unstructured Code Does Not Necessarily
Improve It; Use Profiler Before Optimizing; Conserve Familiarity; The System's Existence Promotes Evolution

Comments
Software rots (we have not much self-modifying sw and the world keeps changing).
Language (use) Affects Maintainability: repeat until death! Beware of fashion.
Sometimes It Is Better to Start Over: Sometimes It would have been Better to Start Over
Renovate the Worst First: Low hanging fruit tastes great!
Belief That a Change Is Easy Makes It Likely It Will Be Made Incorrectly: this can only be learned by mistake :)
The System's Existence Promotes Evolution: Real sw engineers are social engineeers (of a sort).

sábado 31 de mayo de 2008

Design Principles Notes

This notes gather guidance and principles of software design (OO design in particular).
This is a work in progress.
It is hard to create a perfect structure of orthogonal principles as some relate to each other.
Links:
wikipedia
Good: http://www.cmcrossroads.com/bradapp/docs
A Java study: http://javaboutique.internet.com/Case_Study/
Some principles expained: http://www.cs.sjsu.edu/faculty/pearce/cs251b/principles


0. Serenity Principle (SP?): Separate what can change from that that cannot.
God, give us grace to accept with serenity the things that cannot be changed, courage to change the things that should be changed, and the wisdom to distinguish the one from the other.
Common Closure Principle (CCP) Classes that change together must be placed in the same package.
See: Policy and mechanism


1. Liskov Substitution Principle (LSP): All uses of A can be substituted by A' (A' subtype of A).
All base class usages (use define nature, interface) can be substituted by derived classes without external behavior change.
Guides proper inheritance usage. Inheritance should be additive, never restrictive.
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
When extending: Preconditions cannot be straightened, Postconditions cannot be loosened, visible Invariants cannot be changed (?). Invariants: users depend on this both before and after sending a message.
Use a proper set-based inheritance relationship. Not following set semantics is very risky.
Subsumption Rule: A reference to a subtype can be used in any context where a reference to a super type is expected.
This principle extremely limits what SHOULD be done with the pure extension (inheritance) mechanism. Do not follow at your own risk.
Squares aren't Rectangles!
See: http://www.cs.sjsu.edu/faculty/pearce/cs251b/principles/liskov2.htm



2. Dependency Inversion Principle (DIP): Abstractions should not depend upon details. Details should depend upon abstractions.
High-level modules should not depend upon low-level modules. Both should depend upon abstractions.
Depend on abstractions, not implementations.
Program to an interface, not to an implementation. Separate interface from concrete implementations. Depend upon abstractions. Decouple helpers with interfaces.
Do not make high-level (general) classes directly dependent on the implementation of lower-level ones (its helpers).
Abstractions(core client visible, testable, components) should not depend upon details (helpers). Details(helpers) should depend upon abstractions (interfaces): this is the "inversion" , the helper depends upon a new abstraction, and the abstraction no longer depends on the helper directly.
High level or low level modules should not depend upon each other, instead they should depend upon abstractions.
Frees you from having to implement in either a down-top (always runnable and useful) approach or a top-down approach (whole view, structured, progressive refinement) with mock implementations. You are free to decide you implementation strategy guided by: risks, weights, scenarios, ... allows TDD and others.
Allows you to use compositional techniques for program creation: components.
Allows you to test each element in isolation (unit tests) as well as a group of them (functional and scenario tests).
Program to an interface not to an implementation. Corollary: Do not access/modify directly the internal state of a client.
If you depend on a concrete client, you will probably end up depending also on the concrete clients of the client, ad nauseum.
Reify design in code (by not tying yourself to an concrete "future" implementation).
Minimize concrete implementation dependencies.
Note that interfaces in Java are clean but a bit unwieldy and underpowered (see traits in Scala). Requires more concepts.
The Inverted Tree: shown core modules down and and future usage layers on top of it. Inversion: Client (user) code invokes base code. This is the basis of frameworks, independent of implementation technique. Inversion appears when older code will call newer, more refined one (call-backs).
Reify structure and dependencies.
Related: see Facade, Interface, TDD, component, composition, IoC, DI, framework, Spring, Guice
See:
Protocol Stack Example: http://www.eventhelix.com/RealtimeMantra/Object_Oriented/dependency_inversion_principle.htm


3. Open/Closed Principle (OCP): modules should be open for extension, but closed for modification.
Modification can easily break the design of a piece of sw.
Modification requires deep internal knowledge.
Solving a family of problems instead of the concrete one you have to face.This can conflict with YAGNI.
You need to modify if the current design cannot accommodate your extension/use easily.
Embed design decisions and restrictions in the source code (final, protected).

Open/Closed object
Dynamic Dispatch Rule: Objects should decide how to handle the messages they receive.


Open/Closed class
It should be possible to change the implementation of an object without modifying its class.
It should be possible to change the internals of a class without needing to even recompile its clients.
Abstraction Principle: The interface of a module should be independent of its implementation

See: Strategy, State, and Bridge Patterns


Open closed system
Service-Oriented Architecture (SOA) is an Open/Closed architecture for systems.
Reflective systems allow the system to dynamically discover the interfaces implemented by third party components. Each component is expected to implement a meta-interface that describes the application-specific interfaces that it implements.
Separate policy (max change) from mechanism (stable).

Open/Closed principle in HCI:
The most open sw artifact is a language or other building-blocks based solution.
The better closed a sw piece, the easier it is to experiment with it without risk.
Good GUI design uses the Open/Closed principle to guide and present the possible transitions in an intuitive way, without forcing analytical thought: see flow.


4. Design by contract and responsibilities (DBC and RDD)
It is a series of techniques for OOD: guiding the distribution of functionality and its definition and evolution.
DbC involves: preconditions, postconditions, invariants. You get: well-defined interfaces, closed designs (see Open/Closed) easily extensible, a basis for some types of testing, the capacity to fail fast, a way to warrant consistency.
Responsibility Design involves: Objects, responsibilities and collaborations. You get well-decoupled, highly cohesive and easily comprehended classes, well-defined associations and a balanced overall class design.
High Cohesion by responsibilities - Low Coupling by good delegation and concept reification.
See: OOSC for DbC, DOOS for responsibilities


5. Composite Reuse Principle (CRP)
Favor composition over inheritance to achieve polymorphism.
Favor delegation over inheritance. Delegation can be seen as a reuse mechanism at the object level, while inheritance is a reuse mechanism at the class level.
Implementation inheritance is the goto of OOP.
Favor composition over inheritance.
When in doubt, do not inherit.
See: Strategy pattern


6. Modularity Principle (MP): High cohesion and low coupling
Modularity Principle tells us that modules should be cohesive and loosely coupled.
The Facade pattern can lower the coupling degree between modules.
The Mediator pattern can reduce the dependencies between the members of a package.
The members of a subpackage can be considered to be members of the super package (transparent packages) or not (opaque packages, like in Java.)

Acyclic Dependency Principle(ADP): Avoid cycles in the package-level dependency graph
It is sometimes difficult (impossible) to avoid cycles in the class-level dependency graph. But reject packages with cycles!
Interface Segregation Principle (ISP): Many specific interfaces are better than a single, general interface
Release Reuse Equivalency Principle (REP) The granule of release is the granule of reuse.
Common Reuse Principle (CReP) The classes in a package are reused together. If one of the classes in a package is reused, all the classes in that package are reused.
Stable Dependencies Principle (SDP) The dependencies between packages must always be in the direction of stability. Less stable packages should depend on more stable packages.
Stable Abstraction Principle (SAP) The stable packages must be abstract packages. The instable packages should contain the concrete implementations.

Note: Java modularity is incomplete. Both NB & Eclipse add higher abstraction 'packages' (see OSGi)


7. Law of Demeter (LoD) or Principle of Least Knowledge (PLK): Only talk to your friends
A method should only send messages to itself, its parameters, objects it creates (in the method), global objects (of the object/class), and objects it contains (inner of the method or of the object).
Law of Demeter for Functions/Methods (LoD-F): Object A can request a service (call a method) of an object instance B, but object A cannot “reach through” object B to access yet another object to request its services.
A method M of an object O may only invoke the methods of the following kinds of objects:
- O itself
- M's parameters
- any objects created/instantiated within M
- O's direct component objects

Objects are less dependent on the internal structure of other objects, object containers can be changed without reworking their callers.
Use only one dot (approx).
Delegation is an effective technique to avoid Law of Demeter violations, but only for behavior, not for attributes.
Law of Demeter can degrade performance:
Demeter Transmogrifiers: requires writing a large number of small “wrapper” methods to propagate method calls to the components. A class’s interface can become bulky as it hosts methods for contained classes resulting in a class without a cohesive interface.

Law of Demeter for Concerns (LoDC): Only talk to your friends who share your concerns, requires aspects (or traits).

Designing for extension: (frameworks)
Strong Adherence to LoD may be required for reusable class frameworks (usable by client subclasses as well as "normal" clients). Some of the rules they propose are:
- Whenever an object needs to request a service of some other external object, this external service request should be encapsulated in an internal non-public method of the object. This allows derived classes to override the service request with a more specialized one (it is also a use of the GoF Template pattern).
- Whenever an object needs to instantiate some other externally associated object, it should do so using a non-public method to perform the instantiation. This allows derived classes to instantiate a more specialized object if needed.


9. End to End Argument (EEA)
It should be possible to defer work as late as possible (YAGNI)
Avoid intermediate steps.
Lazy evaluation is the general case!
The best optimization is done when all possible affected information is available
See: JIT



OO Tips

Naïve OOAD:
Start with the domain, language analysis helps:
names -> domain objects
adjectives -> derived classes
verbs -> methods
patterns, structure -> design objects

Polymorphism:
- Subsumption Rule: A reference to a subtype can be used in any context where a reference to a super type is expected. (LSP)
- Dynamic Dispatch Rule: Objects decide how to handle the messages they receive.

Divide an app into 1 core and N helper reusable frameworks
Favor immutability for small objects (over get-set beans).
Model classes with complex behavior as state machines
Choose the most restrictive access possible. You will not be able to close it up when there are users.
Structured Programming smells:
- Control-Driven Solutions (switch, case, if, instanceof) point to structured programming, Data-driven solutions are more OO.
- Dynamic checking should be subsumed in the design of the application (avoid instanceof).
- Control modules that hold the logic of multiple components. Control and algorithms are distributed in OO !
Incomplete delegation smells:
- big classes: split into helpers
- multiple get-set: clone, update operations

domingo 11 de mayo de 2008

Some design koans

A good design is worth ten implementations.
A bad architecture can´t be saved by a million developers (in the long run).
Software rots.
Software flexibility comes from the blood of its creators.
Design patterns in a language/framework are code idioms in a better one.
Refactoring is trying to get design out of entropy-full code.
Sw process is how it is done, not what is written or talked about.
You get farther striving for simplicity than for cleverness or features.
Design is what can be said about software without having to read each line of code. The more that needs to be said the worse the design.
Reuse is a dream, but we are allowed to dream. Aren´t we?
Reuse is now at the copy-and-paste level.
Software reuse is what a developer has learned after completing a project.
A software factory is an oxymoron.
Good code can only be appreciated by developers, the effects of bad code are detected by anyone.
Abstraction is the last refuge of the reckless.
As in real life, good looks can hide mean souls.

Those are mine (as far as I know), there are great sw koan writers around, I´ll add links latter.

jueves 1 de mayo de 2008

About roaches & Java: Climbing with grace (with Scala!)

There is some tension around about Java: what is the Next Big Thing(tm)?, is Java mature?  Is Java dead? .... The fact is, as has been said elsewhere, that Java has reached cockroach status: meaning there is no way back. So Java is now on par with Cobol, Fortran and C: code (and work) is not going away! Also Java has set the bar higher than any other roach before it: 
- Cobol: legibility, closeness to user model
- Fortran: numerical and algorithmic expressiveness
- C: portability, simplicity, closeness to underlying  model, speed
- Java: garbage collection, objects, dynamic loading, virtual machine, language interoperability, APIs, IDE ...
For a future aspiring roach it has to at least be able to have the characteristics of all previous roaches. (When I say Java of course you can put .Net if you are living in that closed world).
It seems the dev world is, at last, ready for FP (wether newcomers are ready for it is another question. But newcomers are forced to do what they have to do). And of all the proposed New Things it seems Scala is the thing that retains most good Java things and adds most good "new" things.
What Scala has got now:
1. Exceptional Java interoperability
2. Great (for a non pure FP) functional constructs
3. Better OO than Java (traits, companion objects)
4. Nice core community (and I mean nice, being nice to newcomers and to other players is a must some Gollums have learned the hard way ...)
5. Academic soundness 

What Scala is missing right now (to be on a par with what Java has got):
1. Good tutorial: there is a book in the works that may be of the right level for Java developers. There are a bunch of scattered blog entries around. Missing: use cases and idioms, more Java frameworks-Scala samples
2. API stability and development: more Java helpers-wrappers, better documentation.
3. Killer applications?: Java, and the JVM, is the "killer application" of Scala.  
4. Patronage: Academia is behind Scala but some further industry support is needed. Plugins for main IDEs are on the way, but Scala is a more complex language to support that others.
5. Clearer roadmaps: Although stability is settling up lately, the only way to know where we are heading in the next moths is to check the bug
6. Better visibility: There is a need for more "in the wild" tools, programs, frameworks, applications, API. And this is where most of us should be working on. Start using Scala for some small projects now !