{"id":19153,"date":"2009-02-13T10:00:00","date_gmt":"2009-02-13T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/02\/13\/the-checkbox-the-mating-call-of-the-loser\/"},"modified":"2009-02-13T10:00:00","modified_gmt":"2009-02-13T10:00:00","slug":"the-checkbox-the-mating-call-of-the-loser","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090213-00\/?p=19153","title":{"rendered":"The checkbox: The mating call of the loser"},"content":{"rendered":"<p><P>\n(Cultural note: The phrase\n<I>the mating call of the loser<\/I>\nis a term of derision.\nI used it here to create a more provocative headline\neven though it&#8217;s stronger than I really intended,\nbut\n<A HREF=\"http:\/\/www.deez.info\/sengelha\/2008\/01\/30\/in-writing-precision-often-harms-readability\/\">\ngood writing is bold<\/A>.)\n<\/P>\n<P>\nWhen given a choice between two architectures,\nsome people say that\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/01\/29\/7294949.aspx#7324700\">\nyou should give users a checkbox to select which one should be used<\/A>.\nThat is the ultimate cowardly answer.\nYou can&#8217;t decide between two fundamentally different approaches,\nand instead of picking one, you say\n&#8220;<A HREF=\"http:\/\/www.dilbert.com\/strips\/comic\/1996-01-27\/\">Let&#8217;s do both<\/A>!&#8221;,\nthereby creating triple, perhaps quadruple the work compared\nto just choosing one or the other.\n<\/P>\n<P>\nIt&#8217;s like you&#8217;re remodeling a book library and somebody asks you,\n&#8220;Should we use\n<A HREF=\"http:\/\/www.oclc.org\/dewey\/\">\nDewey Decimal<\/a>\nor\n<A HREF=\"http:\/\/www.loc.gov\/catdir\/cpso\/lcc.html\">\nLibrary of Congress<\/a>?&#8221;\nYour answer, &#8220;Let&#8217;s do both and let the user choose!&#8221;\n<\/P>\n<P>\nImagine if there were a checkbox somewhere in the Control Panel\nthat let you specify how\nWindows&nbsp;XP-styled controls were implemented.\nYour choices are either to require applications to\nlink to a new <CODE>UxCtrl.DLL<\/CODE> (let&#8217;s call this Method&nbsp;A)\nor to link to <CODE>COMCTL32.DLL<\/CODE> with a custom manifest\n(let&#8217;s call this Method&nbsp;B).\nWell, it means that every component that wanted styled common controls\nwould have to come in two versions,\none that linked to <CODE>UxCtrl<\/CODE> and used the new class names\nin its dialog boxes and calls to <CODE>CreateWindow<\/CODE>,\nand one that used a manifest and continued to use the class names\nunder their old names.\n<\/P>\n<PRE>\n#ifdef USE_METHODA\n hwnd = CreateWindow(TEXT(&#8220;UxButton&#8221;), &#8230;);\n#else\n hwnd = CreateWindow(TEXT(&#8220;Button&#8221;), &#8230;);\n#endif<\/p>\n<p>DLG_WHATEVER DIALOG 36, 44, 230, 94\nSTYLE WS_POPUP | WS_CAPTION | WS_SYSMENU |\n      DS_MODALFRAME | DS_SHELLFONT\nCAPTION &#8220;Whatever&#8221;\nBEGIN\n#ifdef USE_METHODA\n    CONTROL         &#8220;Whatever&#8221;,IDC_WHATEVER,&#8221;UxButton&#8221;,\n                    BS_AUTOCHECKBOX | WS_TABSTOP, 14,101,108,9\n#else\n    CONTROL         &#8220;Whatever&#8221;,IDC_WHATEVER,&#8221;Button&#8221;,\n                    BS_AUTOCHECKBOX | WS_TABSTOP, 14,101,108,9\n#endif\n    &#8230;\n<\/PRE>\n<P>\nAt run time, every program would have to check this global setting\nand spawn off either the &#8220;Method A&#8221; binary or the &#8220;Method B&#8221; binary.\n<\/P>\n<P>\nNow you might try to pack this all into a single binary with\nsomething like this:\n<\/P>\n<PRE>\nif (GetSystemMetrics(SM_USEMANIFESTFORSTYLEDCONTROLS)) {\n hwnd = CreateWindow(TEXT(&#8220;Button&#8221;), &#8230;);\n} else {\n hwnd = CreateWindow(TEXT(&#8220;UxButton&#8221;), &#8230;);\n}\n&#8230;<\/p>\n<p>if (GetSystemMetrics(SM_USEMANIFESTFORSTYLEDCONTROLS)) {\n  DialogBox(hInstance,\n            MAKEINTRESOURCE(DLG_TEMPLATE_WITH_OLDNAME_CONTROLS),\n            &#8230;\n} else {\n  DialogBox(hInstance,\n            MAKEINTRESOURCE(DLG_TEMPLATE_WITH_UXCONTROLS),\n            &#8230;\n}\n<\/PRE>\n<P>\nBut it&#8217;s not actually that simple because a lot of decisions take\nplace even before your program starts running.\nFor example, if your program specifies a load-time link to\n<CODE>UXCTRL.DLL<\/CODE>, then that DLL will get loaded before your\nprogram even runs, even if the system switch is set to use Method&nbsp;B.\nA single-binary program that tries to choose between the two methods\nat runtime will have to do some activation context juggling\nand delay-loading.\nHardly a slam dunk.\n<\/P>\n<P>\nOkay, so now you have two versions of every program.\nAnd you also have to decide what should happen if somebody\nwrites and ships a program that uses Method&nbsp;A exclusively,\neven when the system switch is set to Method&nbsp;B.\nDoes everything still work within that program as if Method&nbsp;A\nwere the system setting, while the rest of the system uses Method&nbsp;B?\n(If you go this route, then you&#8217;ve completely undermined the point\nof Method&nbsp;B.\nThe whole point of Method&nbsp;B is to allow programs that\nrely on specific class names to continue working,\nbut this rogue Method&nbsp;A program is running around using the\nwrong class names!)\n<\/P>\n<P>\nNow the entire operating system and application compatibility work\nneeds to be done with the checkbox set both to Method&nbsp;A and to\nMethod&nbsp;B,\nbecause the compatibility impact of each of the methods is quite different.\nOkay, that&#8217;s double the work. Where is triple and quadruple?\n<\/P>\n<P>\nWell, the two different versions of the program need to be kept in sync,\nsince you want them to behave identically.\nThis can of course be managed with judicious use of <CODE>#ifdef<\/CODE>s\nor runtime branches.\nBut you have to remember both ways of doing things\nand be mindful of the two method each time you modify the program.\nSomebody else might come in and &#8220;fix a little bug&#8221;\nor &#8220;add a little feature&#8221; to your program,\nunaware of how your program manages the shuffle of Method&nbsp;A\nversus Method&nbsp;B.\nThe mental effort necessary to remember two different ways of doing\nthe same thing plus having to expend that effort to correct mistakes\nin the code, that&#8217;s the triple.\n<\/P>\n<P>\nThe quadruple?\nI&#8217;m not sure, maybe the ongoing fragility of such a scheme,\nespecially one that, at the end of the day, is a choice between\ntwo things that have no real impact on the typical end user.\n<\/P>\n<P>\nEngineering is about making tradeoffs.\nIf you refuse to make the choice,\nthen you&#8217;re taking the cowardly route\nand ultimately are creating more work for your team.\nInstead of solving problems, you&#8217;re <I>creating them<\/I>.\n<\/P>\n<P>\nAll because you&#8217;re too chicken to make a hard decision.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Cultural note: The phrase the mating call of the loser is a term of derision. I used it here to create a more provocative headline even though it&#8217;s stronger than I really intended, but good writing is bold.) When given a choice between two architectures, some people say that you should give users a checkbox [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-19153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>(Cultural note: The phrase the mating call of the loser is a term of derision. I used it here to create a more provocative headline even though it&#8217;s stronger than I really intended, but good writing is bold.) When given a choice between two architectures, some people say that you should give users a checkbox [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/19153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=19153"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/19153\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=19153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=19153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=19153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}