Re: Immutable Utility Objects
"Daniel" <wellman-pD6z9c7pN/[email protected]> Sat, 03 Dec 2011 19:52:43 -0000
| Newsgroups | gmane.comp.programming.language-of-the-year |
|---|---|
| Message-ID | <[email protected]> |
--sNyGu35alvu7eV8xJAJBudqONviAOpLE0PnuM05 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Here are a few responses which assume Java, where static class methods are = often called class methods - in other languages like Ruby I realize that cl= ass methods are slightly different. I'm including some quotes from Steve F= reeman and Nat Pryce, the authors of JMock, a mocking library for Java. (My own views are fairly similar, so I'll start with these and am happy to = chime in with more points.) Steve Freeman wrote: http://stackoverflow.com/questions/218813/jmock-mocking-a-static-method "We don't support mocking static methods in jMock because it doesn't fit ou= r design approach. We prefer not to use static methods for significant feat= ures that can affect the state of the system. We tend to use them just to s= upport the OO code and make it more readable. That's why we view mocking a = static methods as a hint that there's a problem. One exception is where it'= s in a third-party library, but we would probably wrap that in something mo= re object-oriented anyway." See Nat Pryce's response (the last in the thread here): =16http://comments.gmane.org/gmane.comp.java.jmock.user/2416 "Does the static method have side effects (e.g. change mutable static state)? If so, it's probably best to turn that into an object and give it an interface. You can then mock the interface. If it's a pure function with no side effects, then there's no problem with giving the object under test known inputs and testing how it uses the known outputs from the pure function. If you want to ignore the complexity of the function when testing, then I think you should apply the Strategy pattern. Introduce an interface between the object under test and the strategy, use a strategy implementation that calls (or replaces) the static function in production code, and use stub implementation in tests." --- In [email protected], Steve Wart <steve.wart@...> wrote: > > Why do some people feel so strongly that implementing class-side behavior > is bad design? >=20 > For example, I've got an object with no mutable state, and no required > inheritance, just a set of related utility functions that are needed to > fire off some processing. >=20 > I've heard arguments that this approach "inhibits testing" - but does tha= t > trump the KISS principle? I seem to be able to test just fine. >=20 > After all if I need a singleton, or even multiple instances, there's > nothing stopping me from refactoring. >=20 > Could it be I'm mistaken in the assumption that people think it's bad? > After all most languages these days have a "Math" import that has nothing > but static behavior, and I'm sure there are many other application-specif= ic > examples of this. >=20 > Alternatively, could it be that creating instances to execute all behavio= r > overcomes problems with static semantics? >=20 > Just curious. >=20 > Thanks, > Steve > --sNyGu35alvu7eV8xJAJBudqONviAOpLE0PnuM05 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> </head> <body style="background-color: #fff;"> <span style="display:none"> </span> <!--~-|**|PrettyHtmlStartT|**|-~--> <div id="ygrp-mlmsg" style="position:relative;"> <div id="ygrp-msg" style="z-index: 1;"> <!--~-|**|PrettyHtmlEndT|**|-~--> <div id="ygrp-text" > <p>Here are a few responses which assume Java, where static class methods are often called class methods - in other languages like Ruby I realize that class methods are slightly different. I'm including some quotes from Steve Freeman and Nat Pryce, the authors of JMock, a mocking library for Java.<br> <br> (My own views are fairly similar, so I'll start with these and am happy to chime in with more points.)<br> <br> Steve Freeman wrote:<br> <a href="http://stackoverflow.com/questions/218813/jmock-mocking-a-static-method">http://stackoverflow.com/questions/218813/jmock-mocking-a-static-method</a><br> <br> "We don't support mocking static methods in jMock because it doesn't fit our design approach. We prefer not to use static methods for significant features that can affect the state of the system. We tend to use them just to support the OO code and make it more readable. That's why we view mocking a static methods as a hint that there's a problem. One exception is where it's in a third-party library, but we would probably wrap that in something more object-oriented anyway."<br> <br> See Nat Pryce's response (the last in the thread here):<br> <a href="http://comments.gmane.org/gmane.comp.java.jmock.user/2416">http://comments.gmane.org/gmane.comp.java.jmock.user/2416</a><br> <br> "Does the static method have side effects (e.g. change mutable static<br> state)? If so, it's probably best to turn that into an object and<br> give it an interface. You can then mock the interface.<br> <br> If it's a pure function with no side effects, then there's no problem<br> with giving the object under test known inputs and testing how it uses<br> the known outputs from the pure function.<br> <br> If you want to ignore the complexity of the function when testing,<br> then I think you should apply the Strategy pattern. Introduce an<br> interface between the object under test and the strategy, use a<br> strategy implementation that calls (or replaces) the static function<br> in production code, and use stub implementation in tests."<br> <br> --- In <a href="mailto:pragprog%40yahoogroups.com">[email protected]</a>, Steve Wart <steve.wart@...> wrote:<br> ><br> > Why do some people feel so strongly that implementing class-side behavior<br> > is bad design?<br> > <br> > For example, I've got an object with no mutable state, and no required<br> > inheritance, just a set of related utility functions that are needed to<br> > fire off some processing.<br> > <br> > I've heard arguments that this approach "inhibits testing" - but does that<br> > trump the KISS principle? I seem to be able to test just fine.<br> > <br> > After all if I need a singleton, or even multiple instances, there's<br> > nothing stopping me from refactoring.<br> > <br> > Could it be I'm mistaken in the assumption that people think it's bad?<br> > After all most languages these days have a "Math" import that has nothing<br> > but static behavior, and I'm sure there are many other application-specific<br> > examples of this.<br> > <br> > Alternatively, could it be that creating instances to execute all behavior<br> > overcomes problems with static semantics?<br> > <br> > Just curious.<br> > <br> > Thanks,<br> > Steve<br> ><br> <br> </p> </div> <!--~-|**|PrettyHtmlStart|**|-~--> <div style="color: #fff; height: 0;">__._,_.___</div> <div id="ygrp-actbar" style="clear: both; margin-bottom: 10px; white-space: nowrap; color: #666; padding-top: 15px;"> <div> <a href="mailto:wellman-pD6z9c7pN/[email protected]?subject=Re%3A%20Immutable%20Utility%20Objects" style="margin-right: 0; padding-right: 0;"> Reply to <span style="font-weight: 700;">sender</span></a> | <a href="mailto:[email protected]?subject=Re%3A%20Immutable%20Utility%20Objects"> Reply to <span style="font-weight: 700;">group</span></a> | <a href="http://groups.yahoo.com/group/pragprog/post;_ylc=X3oDMTJxMW9idTZwBF9TAzk3MzU5NzE0BGdycElkAzI4Mzg3MDgEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMjEyBHNlYwNmdHIEc2xrA3JwbHkEc3RpbWUDMTMyMjk0MTk2NQ--?act=reply&messageNum=10212">Reply <span style="font-weight: 700;">via web post</span></a> | <a href="http://groups.yahoo.com/group/pragprog/post;_ylc=X3oDMTJldWZ0MXE5BF9TAzk3MzU5NzE0BGdycElkAzI4Mzg3MDgEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA250cGMEc3RpbWUDMTMyMjk0MTk2NQ--" style="font-weight: 700;">Start a New Topic</a> </div> <a href="http://groups.yahoo.com/group/pragprog/message/10211;_ylc=X3oDMTM2cjgzcGY0BF9TAzk3MzU5NzE0BGdycElkAzI4Mzg3MDgEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMjEyBHNlYwNmdHIEc2xrA3Z0cGMEc3RpbWUDMTMyMjk0MTk2NQR0cGNJZAMxMDIxMQ--">Messages in this topic</a> (<span style="font-weight: 700;">2</span>) </div> <!------- Start Nav Bar ------> <!-- |**|begin egp html banner|**| --> <div id="ygrp-vital" style="background-color: #e0ecee; font-family: Verdana; font-size: 10px; margin-bottom: 10px; padding: 10px;"> <span id="vithd" style="font-weight: bold; color: #333; text-transform: uppercase; ">Recent Activity:</span> <ul style="list-style-type: none; margin: 0; padding: 0; display: inline;"> </ul> <div style="clear: both; padding-top: 2px; color: #1e66ae;"> <a href="http://groups.yahoo.com/group/pragprog;_ylc=X3oDMTJlYjU2b2xlBF9TAzk3MzU5NzE0BGdycElkAzI4Mzg3MDgEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwN2dGwEc2xrA3ZnaHAEc3RpbWUDMTMyMjk0MTk2NQ--" style="text-decoration: none;">Visit Your Group</a> </div> </div> <div id="ygrp-mkp" style="border: 1px solid #d8d8d8; clear: both; float: left; font-family: Arial; margin: 5px 0 10px 0; padding: 0 10px;"> <div id="hd" style="color: #628c2a; font-size: 85%; font-weight: 700; line-height: 122%; margin: 10px 0;">MARKETPLACE</div> <div id="ads" style="margin-bottom: 10px;"> <div class="ad" style="color: #628C2A; font-family: Arial; font-weight: 700; padding: 0 0;"> <p><a href="http://global.ard.yahoo.com/SIG=15os0gsj2/M=493064.14543979.14562481.13298430/D=groups/S=1705007207:MKP1/Y=YAHOO/EXP=1322949165/L=5ee66aa8-1de8-11e1-9f7d-2b472c0ee353/B=TGO3NUoGYrc-/J=1322941965996058/K=2po.ZNAso_DwqgRpHTXGsg/A=6060255/R=0/SIG=1194m4keh/*http://us.toolbar.yahoo.com/?.cpdl=grpj">Stay on top of your group activity without leaving the page you're on - Get the Yahoo! Toolbar now.</a></p> <script language=javascript> if(window.yzq_d==null)window.yzq_d=new Object(); window.yzq_d['TGO3NUoGYrc-']='&U=13c1r4epj%2fN%3dTGO3NUoGYrc-%2fC%3d493064.14543979.14562481.13298430%2fD%3dMKP1%2fB%3d6060255%2fV%3d1'; </script><noscript><img width=1 height=1 alt="" src="http://us.bc.yahoo.com/b?P=5ee66aa8-1de8-11e1-9f7d-2b472c0ee353&T=1dh1eb1u5%2fX%3d1322941965%2fE%3d1705007207%2fR%3dgroups%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d4195089707%2fH%3dY29udGVudD0iWWFob29fVGVjaDtHbztXaWRnZXRzO1dlYnNpdGVfU2VydmljZXM7UG9kY2FzdHM7RmxpY2tyO1lhaG9vX1NlYXJjaF9NYXJrZXRpbmc7RmluYW5jZTtCcmllZmNhc2U7Q2FsZW5kYXI7IiBkaXNhYmxlc2h1ZmZsaW5nPSIxIiBzZXJ2ZUlkPSI1ZWU2NmFhOC0xZGU4LTExZTEtOWY3ZC0yYjQ3MmMwZWUzNTMiIHNpdGVJZD0iNDQ1MjU1MSIgdFN0bXA9IjEzMjI5NDE5NjU5NjA2NDUiIA--%2fQ%3d-1%2fS%3d1%2fJ%3d27228962&U=13c1r4epj%2fN%3dTGO3NUoGYrc-%2fC%3d493064.14543979.14562481.13298430%2fD%3dMKP1%2fB%3d6060255%2fV%3d1"></noscript><!--QYZ ,;;MKP1;1705007207;2;--> </div> </div> </div> <div id="ft" style="font-family: Arial; font-size: 11px; margin-top: 5px; padding: 0 2px 0 0; clear: both;"> <a href="http://groups.yahoo.com/;_ylc=X3oDMTJkY3Rma2Z2BF9TAzk3MzU5NzE0BGdycElkAzI4Mzg3MDgEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2dmcARzdGltZQMxMzIyOTQxOTY1" style="float: left;"><img src="http://l.yimg.com/a/i/us/yg/logo/us.gif" height="15" width="137" alt="Yahoo! Groups" style="border: 0;"/></a> <div style="color: #747575; float: right;">Switch to: <a href="mailto:[email protected]?subject=Change Delivery Format: Traditional" style="text-decoration: none;">Text-Only</a>, <a href="mailto:[email protected]?subject=Email Delivery: Digest" class="margin-rt" style="text-decoration: none;">Daily Digest</a> • <a href="mailto:[email protected]?subject=Unsubscribe" style="text-decoration: none;">Unsubscribe</a> • <a href="http://docs.yahoo.com/info/terms/" style="text-decoration: none;">Terms of Use</a></div> </div> <!-- |**|end egp html banner|**| --> </div> <!-- ygrp-msg --> <!-- Sponsor --> <!-- |**|begin egp html banner|**| --> <div id="ygrp-sponsor" style="width:160px; float:right; clear:none; margin:0 0 25px 0; background: #fff;"> <!-- Start Recommendations --> <div id="ygrp-reco"> </div> <!-- End Recommendations --> </div> <!-- |**|end egp html banner|**| --> <div style="clear:both; color: #FFF; font-size:1px;">.</div> </div> <img src="http://geo.yahoo.com/serv?s=97359714/grpId=2838708/grpspId=1705007207/msgId=10212/stime=1322941965/nc1=3848642/nc2=4507179/nc3=5758219" width="1" height="1"> <br> <div style="color: #fff; height: 0;">__,_._,___</div> <!--~-|**|PrettyHtmlEnd|**|-~--> </body> <!--~-|**|PrettyHtmlStart|**|-~--> <head> <style type="text/css"> <!-- #ygrp-mkp { border: 1px solid #d8d8d8; font-family: Arial; margin: 10px 0; padding: 0 10px; } #ygrp-mkp hr { border: 1px solid #d8d8d8; } #ygrp-mkp #hd { color: #628c2a; font-size: 85%; font-weight: 700; line-height: 122%; margin: 10px 0; } #ygrp-mkp #ads { margin-bottom: 10px; } #ygrp-mkp .ad { padding: 0 0; } #ygrp-mkp .ad p { margin: 0; } #ygrp-mkp .ad a { color: #0000ff; text-decoration: none; } #ygrp-sponsor #ygrp-lc { font-family: Arial; } #ygrp-sponsor #ygrp-lc #hd { margin: 10px 0px; font-weight: 700; font-size: 78%; line-height: 122%; } #ygrp-sponsor #ygrp-lc .ad { margin-bottom: 10px; padding: 0 0; } a { color: #1e66ae; } #actions { font-family: Verdana; font-size: 11px; padding: 10px 0; } #activity { background-color: #e0ecee; float: left; font-family: Verdana; font-size: 10px; padding: 10px; } #activity span { font-weight: 700; } #activity span:first-child { text-transform: uppercase; } #activity span a { color: #5085b6; text-decoration: none; } #activity span span { color: #ff7900; } #activity span .underline { text-decoration: underline; } .attach { clear: both; display: table; font-family: Arial; font-size: 12px; padding: 10px 0; width: 400px; } .attach div a { text-decoration: none; } .attach img { border: none; padding-right: 5px; } .attach label { display: block; margin-bottom: 5px; } .attach label a { text-decoration: none; } blockquote { margin: 0 0 0 4px; } .bold { font-family: Arial; font-size: 13px; font-weight: 700; } .bold a { text-decoration: none; } dd.last p a { font-family: Verdana; font-weight: 700; } dd.last p span { margin-right: 10px; font-family: Verdana; font-weight: 700; } dd.last p span.yshortcuts { margin-right: 0; } div.attach-table div div a { text-decoration: none; } div.attach-table { width: 400px; } div.file-title a, div.file-title a:active, div.file-title a:hover, div.file-title a:visited { text-decoration: none; } div.photo-title a, div.photo-title a:active, div.photo-title a:hover, div.photo-title a:visited { text-decoration: none; } div#ygrp-mlmsg #ygrp-msg p a span.yshortcuts { font-family: Verdana; font-size: 10px; font-weight: normal; } .green { color: #628c2a; } .MsoNormal { margin: 0 0 0 0; } o { font-size: 0; } #photos div { float: left; width: 72px; } #photos div div { border: 1px solid #666666; height: 62px; overflow: hidden; width: 62px; } #photos div label { color: #666666; font-size: 10px; overflow: hidden; text-align: center; white-space: nowrap; width: 64px; } #reco-category { font-size: 77%; } #reco-desc { font-size: 77%; } .replbq { margin: 4px; } #ygrp-actbar div a:first-child { /* border-right: 0px solid #000;*/ margin-right: 2px; padding-right: 5px; } #ygrp-mlmsg { font-size: 13px; font-family: Arial, helvetica,clean, sans-serif; *font-size: small; *font: x-small; } #ygrp-mlmsg table { font-size: inherit; font: 100%; } #ygrp-mlmsg select, input, textarea { font: 99% Arial, Helvetica, clean, sans-serif; } #ygrp-mlmsg pre, code { font:115% monospace; *font-size:100%; } #ygrp-mlmsg * { line-height: 1.22em; } #ygrp-mlmsg #logo { padding-bottom: 10px; } #ygrp-mlmsg a { color: #1E66AE; } #ygrp-msg p a { font-family: Verdana; } #ygrp-msg p#attach-count span { color: #1E66AE; font-weight: 700; } #ygrp-reco #reco-head { color: #ff7900; font-weight: 700; } #ygrp-reco { margin-bottom: 20px; padding: 0px; } #ygrp-sponsor #ov li a { font-size: 130%; text-decoration: none; } #ygrp-sponsor #ov li { font-size: 77%; list-style-type: square; padding: 6px 0; } #ygrp-sponsor #ov ul { margin: 0; padding: 0 0 0 8px; } #ygrp-text { font-family: Georgia; } #ygrp-text p { margin: 0 0 1em 0; } #ygrp-text tt { font-size: 120%; } #ygrp-vital ul li:last-child { border-right: none !important; } --> </style> </head> <!--~-|**|PrettyHtmlEnd|**|-~--> </html> <!-- end group email --> --sNyGu35alvu7eV8xJAJBudqONviAOpLE0PnuM05--