Five Considerations for Software Architects

Kevlin Henney [email protected]

Economy There's nothing long-winded about "Liberté, égalité, fraternité". Maurice Saatchi Continuing existence or cessation of existence: those are the scenarios. Is it more empowering mentally to work towards an accommodation of the downsizings and negative outcomes of adversarial circumstance, or would it be a greater enhancement of the bottom line to move forwards to a challenge to our current difficulties, and, by making a commitment to opposition, to effect their demise? Tom Burton, Long Words Bother Me To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? William Shakespeare, Hamlet #ifndef BOOST_LEXICAL_CAST_INCLUDED typename stringstream::type interpreter(arg); &>::do_cast(arg); // mpl::apply_if doesn't work well for MSVC 6 here, and neither does #define BOOST_LEXICAL_CAST_INCLUDED #endif } // inheriting from a metafunction

// lexical_cast.hpp header ------// setup_interpreter(interpreter); template // inline std::basic_string struct select_base // See http://www.boost.org for most recent version including documentation. Target result; lexical_cast_impl(std::basic_string *, Source arg) { // { typename mpl::if_, // Target==char? // what: lexical_cast custom keyword cast if(!(interpreter >> result) || !(interpreter >> std::ws).eof()) return any_to_string_base, Source, typename mpl::if_, // Source==char? // who: contributed by Kevlin Henney and enhanced by Terje Slettebø throw detail::no_lexical_conversion(); CharType>::do_cast(arg); direct_cast_base, // when: November 2000, March 2003 } typename mpl::if_, // Source==char *? return result; pointer_to_char_to_char_base, #include } template typename mpl::if_, // Source==const char *? #include }; inline std::basic_string pointer_to_char_to_char_base, #include lexical_cast_impl(std::basic_string *, CharType arg) typename mpl::if_, // Source==std::string? #include ////////////////////////////////////////////////////////////////////////// { string_to_char_base, #include // any_to_string_base return char_to_string_base, CharType>::do_cast(arg); lexical_cast_base ////////////////////////////////////////////////////////////////////////// } >::type #ifdef BOOST_NO_STRINGSTREAM >::type #include template template >::type #else struct any_to_string_base inline std::basic_string >::type, #include { lexical_cast_impl(std::basic_string *, CharType *arg) typename mpl::if_, // Target==std::string? #endif static Target do_cast(Source arg) { typename mpl::if_, // Source==char? { return direct_cast_base, CharType *>::do_cast(arg); char_to_string_base, #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || \ typename stringstream::type interpreter; } typename mpl::if_, // Source==char *? defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) setup_interpreter(interpreter); direct_cast_base, #include if(!(interpreter << arg)) template typename mpl::if_, // Source==const char *? #include throw detail::no_lexical_conversion(); inline std::basic_string direct_cast_base, #endif return interpreter.str(); lexical_cast_impl(std::basic_string *, const CharType *arg) typename mpl::if_, // Source==std::string? } { direct_cast_base, namespace boost }; return direct_cast_base, const CharType any_to_string_base { *>::do_cast(arg); >::type // exception used to indicate runtime lexical_cast failure template } >::type class bad_lexical_cast : public std::bad_cast struct string_to_char_base >::type { { template >::type, public: static Target do_cast(Source arg) inline Target lexical_cast_impl(Target *, char *arg) typename mpl::if_, // Target==wchar_t? virtual ~bad_lexical_cast() throw() { { typename mpl::if_, // Source==wchar_t? { if(arg.length()!=1) return string_to_any_base::do_cast(arg); direct_cast_base, } throw detail::no_lexical_conversion(); } typename mpl::if_, // Source==wchar_t *? }; return arg[0]; pointer_to_char_to_char_base, } template typename mpl::if_, // Source==const wchar_t *? namespace detail }; inline Target lexical_cast_impl(Target *, const char *arg) pointer_to_char_to_char_base, { { typename mpl::if_, // Source==std::wstring? template template return string_to_any_base::do_cast(arg); string_to_char_base, class no_lexical_conversion : public bad_lexical_cast struct pointer_to_char_to_char_base } lexical_cast_base { { >::type public: static Target do_cast(Source arg) template >::type no_lexical_conversion() { inline Target lexical_cast_impl(Target *, wchar_t arg) >::type : description( if(arg[0] == Target() || arg[1] != Target()) { >::type, std::string() + "bad lexical cast: " + throw detail::no_lexical_conversion(); return lexical_cast_base::do_cast(arg); typename mpl::if_, // Target==std::wstring? "source type value could not be interpreted as target, Target=" + return arg[0]; } typename mpl::if_, // Source==wchar_t? typeid(Target).name() + ", Source=" + typeid(Source).name()) } char_to_string_base, { }; template typename mpl::if_, // Source==wchar_t *? } inline Target lexical_cast_impl(Target *, wchar_t *arg) direct_cast_base, virtual ~no_lexical_conversion() throw() template { typename mpl::if_, // Source==const wchar_t *? { struct char_to_string_base return string_to_any_base::do_cast(arg); direct_cast_base, } { } typename mpl::if_, // Source==std::wstring? virtual const char *what() const throw() static Target do_cast(Source arg) direct_cast_base, { { template any_to_string_base return description.c_str(); return Target(1, arg); inline Target lexical_cast_impl(Target *, const wchar_t *arg) >::type } } { >::type private: }; return string_to_any_base::do_cast(arg); >::type const std::string description; // static initialization fails on MSVC6 } >::type, }; template typename mpl::if_, // Target==Source? } struct direct_cast_base template direct_cast_base, { inline Target lexical_cast_impl(Target *, const std::basic_string &arg) typename mpl::if_, // Source==char *? namespace detail static Target do_cast(Source arg) { string_to_any_base, { { return string_to_any_base, // Source==const template return arg; const std::basic_string &, CharType>::do_cast(arg); char *? struct stringstream } } string_to_any_base, { }; typename mpl::if_, // #if defined(BOOST_NO_STRINGSTREAM) template Source==std::string? typedef std::strstream type; #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && \ inline Type lexical_cast_impl(Type *, const Type &arg) string_to_any_base, #else !defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) { typename mpl::if_, // Source==wchar_t? typedef std::basic_stringstream type; return direct_cast_base::do_cast(arg); lexical_cast_base, #endif template } typename mpl::if_, // Source==wchar_t }; inline Target lexical_cast_impl(Target *, Source arg) *? { inline std::string lexical_cast_impl(std::string *, char *arg) lexical_cast_base, template return lexical_cast_base::do_cast(arg); { typename mpl::if_, // Source==const void setup_interpreter(Interpreter &interpreter) } return direct_cast_base::do_cast(arg); wchar_t *? { } lexical_cast_base, interpreter.unsetf(std::ios_base::skipws); template typename mpl::if_, // void lexical_cast_impl(Target **,Source) inline std::string lexical_cast_impl(std::string *, const char *arg) Source==std::wstring? if(std::numeric_limits::is_specialized) { { lexical_cast_base, interpreter.precision(std::numeric_limits::digits10 + 1); BOOST_STATIC_ASSERT((Target **) 0); // Pointer as target type not supported return direct_cast_base::do_cast(arg); lexical_cast_base else if(std::numeric_limits::is_specialized) } } >::type interpreter.precision(std::numeric_limits::digits10 + 1); >::type } inline char lexical_cast_impl(char *, char *arg) inline std::string lexical_cast_impl(std::string *, const std::string &arg) >::type { { >::type template return pointer_to_char_to_char_base::do_cast(arg); return direct_cast_base::do_cast(arg); >::type struct lexical_cast_base } } >::type { >::type static Target do_cast(Source arg) inline char lexical_cast_impl(char *, const char *arg) inline std::wstring lexical_cast_impl(std::wstring *, wchar_t *arg) >::type { { { >::type typename stringstream::type interpreter; return pointer_to_char_to_char_base::do_cast(arg); return direct_cast_base::do_cast(arg); >::type } } >::type setup_interpreter(interpreter); >::type type; template inline std::wstring lexical_cast_impl(std::wstring *, const wchar_t *arg) }; Target result; inline wchar_t lexical_cast_impl(wchar_t *, Source arg) { { return direct_cast_base::do_cast(arg); if(!(interpreter << arg) || !(interpreter >> result) || return lexical_cast_base::do_cast(arg); } template !(interpreter >> std::ws).eof()) } inline Target lexical_cast_impl(Target *, Source arg) throw detail::no_lexical_conversion(); inline std::wstring lexical_cast_impl(std::wstring *, const std::wstring &arg) { inline wchar_t lexical_cast_impl(wchar_t *, wchar_t *arg) { return select_base::type::do_cast(arg); return result; { return direct_cast_base::do_cast(arg); } } return pointer_to_char_to_char_base::do_cast(arg); } #endif }; } } inline wchar_t lexical_cast_impl(wchar_t *, wchar_t arg) ////////////////////////////////////////////////////////////////////////// inline wchar_t lexical_cast_impl(wchar_t *, const wchar_t *arg) { template // string_to_any_base { return direct_cast_base::do_cast(arg); inline Target lexical_cast(const Source &arg) ////////////////////////////////////////////////////////////////////////// return pointer_to_char_to_char_base::do_cast(arg); } { } return detail::lexical_cast_impl(static_cast(0), arg); template inline std::wstring lexical_cast_impl(std::wstring *, wchar_t arg) } struct string_to_any_base inline wchar_t lexical_cast_impl(wchar_t *, const std::wstring &arg) { } { { return char_to_string_base::do_cast(arg); static Target do_cast(Source arg) return string_to_char_base::do_cast(arg); } // Copyright Kevlin Henney, 2000-2003, Terje Slettebø, 2003. All rights reserved. { } // #ifdef BOOST_NO_STRINGSTREAM #else // Permission to use, copy, modify, and distribute this software for any typename stringstream::type interpreter; template // purpose is hereby granted without fee, provided that this copyright and inline CharType // Simulated partial specialisation // permissions notice appear in all copies and derivatives. if(!(interpreter << arg)) lexical_cast_impl(CharType *, const std::basic_string &arg) // select_base // throw detail::no_lexical_conversion(); { ////////////////////////////////////////////////////////////////////////// // This software is provided "as is" without express or implied warranty. #else return string_to_char_base #endif #ifndef BOOST_LEXICAL_CAST_INCLUDED struct stream_char #define BOOST_LEXICAL_CAST_INCLUDED { typedef wchar_t type; // Boost lexical_cast.hpp header ------// }; // #endif // See http://www.boost.org for most recent version including documentation. // See end of this header for rights and permissions. template // struct widest_char // what: lexical_cast custom keyword cast { // who: contributed by Kevlin Henney, typedef TargetChar type; // enhanced with contributions from Terje Slettebø, }; // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, template<> // and other Boosters struct widest_char // when: November 2000, March 2003 { typedef wchar_t type; #include }; #include } #include #include namespace detail // stream wrapper for handling lexical conversions #include { template #ifdef BOOST_NO_STRINGSTREAM class lexical_stream #include { #else public: #include lexical_stream() #endif { stream.unsetf(std::ios::skipws); #if defined(BOOST_NO_STRINGSTREAM) || \ defined(BOOST_NO_STD_WSTRING) || \ if(std::numeric_limits::is_specialized) defined(BOOST_NO_STD_LOCALE) || \ stream.precision(std::numeric_limits::digits10 + 1); defined(BOOST_NO_CWCHAR) else if(std::numeric_limits::is_specialized) #define DISABLE_WIDE_CHAR_SUPPORT stream.precision(std::numeric_limits::digits10 + 1); #endif } ~lexical_stream() #ifdef BOOST_NO_INTRINSIC_WCHAR_T { #include #if defined(BOOST_NO_STRINGSTREAM) #endif stream.freeze(false); #endif namespace boost } { bool operator<<(const Source &input) // exception used to indicate runtime lexical_cast failure { class bad_lexical_cast : public std::bad_cast return stream << input; { } public: template virtual ~bad_lexical_cast() throw() bool operator>>(InputStreamable &output) { { } return !is_pointer::value && }; stream >> output && (stream >> std::ws).eof(); namespace detail // actual underlying concrete exception type } { bool operator>>(std::string &output) template { class no_lexical_conversion : public bad_lexical_cast #if defined(BOOST_NO_STRINGSTREAM) { stream << '\0'; public: #endif no_lexical_conversion() output = stream.str(); : description( return true; std::string() + "bad lexical cast: " + } "source type value could not be interpreted as target, Target=" + #ifndef DISABLE_WIDE_CHAR_SUPPORT typeid(Target).name() + ", Source=" + typeid(Source).name()) bool operator>>(std::wstring &output) { { } output = stream.str(); virtual ~no_lexical_conversion() throw() return true; { } } #endif virtual const char *what() const throw() private: { typedef typename widest_char< return description.c_str(); typename stream_char::type, } typename stream_char::type>::type char_type; private: const std::string description; // static initialization fails on MSVC6 #if defined(BOOST_NO_STRINGSTREAM) }; std::strstream stream; } #elif defined(BOOST_NO_STD_LOCALE) std::stringstream stream; namespace detail // selectors for choosing stream character type #else { std::basic_stringstream stream; template #endif struct stream_char }; { } typedef char type; }; template Target lexical_cast(Source arg) #ifndef DISABLE_WIDE_CHAR_SUPPORT { template<> detail::lexical_stream interpreter; struct stream_char Target result; { typedef wchar_t type; if(!(interpreter << arg && interpreter >> result)) }; throw detail::no_lexical_conversion(); return result; template<> } struct stream_char } { typedef wchar_t type; // Copyright Kevlin Henney, 2000-2003. All rights reserved. }; // // Permission to use, copy, modify, and distribute this software for any template<> // purpose is hereby granted without fee, provided that this copyright and struct stream_char // permissions notice appear in all copies and derivatives. { // typedef wchar_t type; // This software is provided "as is" without express or implied warranty. }; #undef DISABLE_WIDE_CHAR_SUPPORT template<> #endif The difference between a good and a poor architect is that the poor architect succumbs to every temptation and the good one resists it. Ludwig Wittgenstein interface Iterator { boolean set_to_first_element(); boolean set_to_next_element(); boolean set_to_next_nth_element(in unsigned long n) raises(…); boolean retrieve_element(out any element) raises(…); boolean retrieve_element_set_to_next(out any element, out boolean more) raises(…); boolean retrieve_next_n_elements(in unsigned long n, out AnySequence result, out boolean more) raises(…); boolean not_equal_retrieve_element_set_to_next(in Iterator test, out any element) raises(…); void remove_element() raises(…); boolean remove_element_set_to_next() raises(…); boolean remove_next_n_elements(in unsigned long n, out unsigned long actual_number) raises(…); boolean not_equal_remove_element_set_to_next(in Iterator test) raises(…); void replace_element(in any element) raises(…); boolean replace_element_set_to_next(in any element) raises(…); boolean replace_next_n_elements(in AnySequence elements, out unsigned long actual_number) raises(…); boolean not_equal_replace_element_set_to_next(in Iterator test, in any element) raises(…); boolean add_element_set_iterator(in any element) raises(…); boolean add_n_elements_set_iterator(in AnySequence elements, out unsigned long actual_number) raises(…); void invalidate(); boolean is_valid(); boolean is_in_between(); boolean is_for(in Collection collector); boolean is_const(); boolean is_equal(in Iterator test) raises(…); Iterator clone(); void assign(in Iterator from_where) raises(…); void destroy(); }; interface BindingIterator { boolean next_one(out Binding result); boolean next_n(in unsigned long how_many, out BindingList result); void destroy(); }; That which is overdesigned, too highly specific, anticipates outcome; the anticipation of outcome guarantees, if not failure, the absence of grace. William Gibson, All Tomorrow's Parties There have always been fairly severe size constraints on the Unix operating system and its software. Given the partially antagonistic desires for reasonable efficiency and expressive power, the size constraint has encouraged not only economy but a certain elegance of design.

Dennis Ritchie and Ken Thompson Visibility The cause is hidden. The effect is visible to all. Ovid

Test Early. Test Often. Test Automatically. Andrew Hunt and David Thomas The Pragmatic Programmer B A ⊗ ⊗ ⊗ ⊗ ⊗

D E ⊗ ⊗ ⊗ ⊗ ⊗ ⊗ ⊗ ⊗ ⊗

F

Patterns help to mark out and make design decisions visible and communicable. A pattern focuses on context and forces that relate to a design situation. Pattern sequences highlight incremental growth, making progress visible. Spacing

Core External Root Code Wrapper

Wrapped

Core Usage Root Code Interface

External Wrapper

Decoupled Client Name based on implementation

Implementation name

Client Name based on client usage

Implementation name • •

• • • • • •

Consider a number of possible Dependency inversion allows a design's change scenarios and mark dependencies to be reversed, loosened affected components. and manipulated at will, which means that dependencies can be aligned with known or anticipated stability. Symmetry symmetry the quality of being made up of exactly similar parts facing each other or around an axis. ƒ correct or pleasing proportion of the parts of a thing. ƒ similarity of exact correspondence between different things. The New Oxford Dictionary of English When in doubt, make it symmetrical. Christopher Alexander Victor Hugo

La symétrie, c'est l'ennui, et l'ennui est le fond même du deuil. Le désespoir baîlle. Factory Client factoryMethod Product disposalMethod

? Concrete Factory «create» factoryMethod Concrete disposalMethod Product «destroy» Client Client

Feature

Option A Option B Option A Option B Emergence Flocking is a common demonstration of emergent behaviour.... The result is alike to a flock of birds, a school of fish, or swarm of insects. Basic flocking is controlled by three simple rules: 1. Separation avoid crowding neighbours 2. Alignment steer towards average heading of neighbours 3. Cohesion steer towards average position of neighbours With these three simple rules, the flock moves in an extremely realistic way, creating complex motion and interaction that would be extremely hard to create otherwise. Wikipedia 〈key, data, state: {A, B, C, D} , locked?〉

process from B to C

process from A to B

process from C to D begins in process state A from A to B

〈key, data〉

process queue for from B to C state B

〈key, data〉

process queue for from C to D state C

completes in state D If practice is unprincipled there is no coordination and there is discord. When it is principled, there is balance, harmony and union. Perhaps all life aspires to the condition of music. Aubrey Meyer