<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The Audio Fool : Programming</title><link>http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx</link><description>Tags: Programming</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>You can't hear DC</title><link>http://blogs.msdn.com/audiofool/archive/2007/06/21/you-can-t-hear-dc.aspx</link><pubDate>Thu, 21 Jun 2007 20:00:58 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3445707</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/3445707.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=3445707</wfw:commentRss><description>&lt;p&gt;Recently one of my team members found a bug in some old code while doing a code review.&amp;nbsp; Our application was generating a sine wave to be rendered by the audio hardware.&amp;nbsp; The sample format isn't important except to note that it is an unsigned value between 0 and MAX = 2*FS_AMP.&amp;nbsp; The bug is in the following code.&lt;/p&gt; &lt;table cellspacing="0" cellpadding="2" width="574" border="0" unselectable="on"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="572"&gt; &lt;p&gt;void GenerateSineWave(float buffer[], float frequency, float amplitude) {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // frequency in Hz, amplitude in range(0.0, 1.0)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float w = 2 * PI * frequency / SAMPLE_RATE;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for&amp;nbsp;(int t = 0; t &amp;lt; NUMBER_OF_SAMPLES; t++)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; float sample = sin(w * t) * FS_AMP //&amp;nbsp;full scale sine wave&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sample += FS_AMP; // Move into positive range&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sample *= amplitude;&amp;nbsp; // Scale to&amp;nbsp;requested amplitude&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; buffer[t] = sample;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;So do you see the bug?&amp;nbsp; After this code, we have a sine wave that oscillates between 0 and 2*amplitude*FS_AMP.&amp;nbsp; For amplitude = 1.0, this is exactly what we want, but for any smaller amplitude, the wave is low-justified in the sample range.&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/audiofool/WindowsLiveWriter/9329c0513632_786A/smsin_bottom_2.png" atomicselection="true"&gt;&lt;img height="115" alt="smsin_bottom" src="http://blogs.msdn.com/blogfiles/audiofool/WindowsLiveWriter/9329c0513632_786A/smsin_bottom_thumb_2.png" width="579"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;What we really wanted here is a signal that is center-justified in the range, such as below.&amp;nbsp; We were sending the wrong samples!&lt;/p&gt; &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/audiofool/WindowsLiveWriter/9329c0513632_786A/smsin_ctr_1.png" atomicselection="true"&gt;&lt;img height="115" alt="smsin_ctr" src="http://blogs.msdn.com/blogfiles/audiofool/WindowsLiveWriter/9329c0513632_786A/smsin_ctr_thumb_1.png" width="579"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The fix is fairly simple.&amp;nbsp; We want to scale (*= amplitude) before we translate (+= FS_AMP).&amp;nbsp; Then we get a sine wave that oscillates between (FS_AMP *(1-amplitude)) and (FS_AMP * (1+amplitude)).&lt;/p&gt; &lt;p&gt;After fixing a bug in old code, the next question we have to ask ourselves is why we missed it.&amp;nbsp; How come this bug wasn't found in&amp;nbsp;a test pass when it was written, or any time in between?&amp;nbsp; The answer is almost as subtle as the code that caused the problem.&amp;nbsp; From an audio perspective, the bug had no impact at all.&lt;/p&gt; &lt;p&gt;The buffer generated by this buggy code was sent directly to the DAC on the hardware.&amp;nbsp; The signal does not clip, and it's not distorted.&amp;nbsp; All of the sine components are the same.&amp;nbsp; If you got an FFT on each of the two sine waves above, they would differ only in the very first bin, the one corresponding to the DC component of the signal.&lt;/p&gt; &lt;p&gt;But you can't hear DC.&lt;/p&gt; &lt;p&gt;DC is essentially the baseline for a signal.&amp;nbsp; The value from which the signal wave deviates in time.&amp;nbsp; The measured level of silence.&amp;nbsp; For a speaker, the DC level is the distance of the cone when unplugged.&amp;nbsp; For the atmosphere, DC is about 14psi (or 1.0 atm) at sea level.&lt;/p&gt; &lt;p&gt;For a digital signal stored as numbers, DC can be any arbitrary value.&amp;nbsp; In a computer which have a fixed minimum and maximum, we usually choose&amp;nbsp;halfway between min and max because it offers the most dynamic range.&amp;nbsp;&amp;nbsp;This also explains why most audio formats use signed numbers for samples rather than unsigned.&amp;nbsp;&amp;nbsp;The center of the allowed range for a signed number is zero, and&amp;nbsp;zero is a very easy number to work with.&amp;nbsp; In the code&amp;nbsp;snippet above, the bug would not manifest if we were using signed numbers, because the translation step for signed numbers is a no-op.&lt;/p&gt; &lt;p&gt;One other way of looking at DC is as a wave with frequency zero, and an infinite wavelength.&amp;nbsp; Since zero is below the lowest frequency a human can hear (about 20Hz), you can't hear it.&amp;nbsp;&amp;nbsp;Q.E.D.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Epilogue&lt;/strong&gt;:&amp;nbsp;This bug &lt;em&gt;does&lt;/em&gt; show up as a frequency component any time we dynamically alter the amplitude while streaming,&amp;nbsp;so we fixed&amp;nbsp;it.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3445707" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Audio/default.aspx">Audio</category><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category></item><item><title>The Rules of Code Optimization</title><link>http://blogs.msdn.com/audiofool/archive/2007/06/14/the-rules-of-code-optimization.aspx</link><pubDate>Thu, 14 Jun 2007 20:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3297488</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/3297488.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=3297488</wfw:commentRss><description>&lt;p&gt;&lt;a href="http://blogs.msdn.com/steverowe/" target="_blank" mce_href="http://blogs.msdn.com/steverowe/"&gt;Steve Rowe&lt;/a&gt; recently talks about &lt;a href="http://blogs.msdn.com/steverowe/archive/2007/06/12/coding-for-humans.aspx" mce_href="http://blogs.msdn.com/steverowe/archive/2007/06/12/coding-for-humans.aspx"&gt;who you're really writing for&lt;/a&gt; when you write code.&amp;nbsp; The argument he makes is essentially that your primary audience is not the compiler, but rather your primary audience is other developers.&amp;nbsp; This is something I believe strongly.&lt;/p&gt;

&lt;p&gt;Steve also makes a point about premature optimization, and how it affects readability.&amp;nbsp; This reminded me of a list of the Rules of Optimization that I try to live by:&lt;/p&gt;
&lt;hr&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;The First Rule of Code Optimization&lt;/b&gt;: Don't. &lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimizing code has a negative effect on readability and maintainability.&amp;nbsp; The vast majority of code doesn't need to run particularly fast, but it all needs to be maintainable.&amp;nbsp; Even programs you think are one-off and temporary have a tendency to become permanent.&lt;/p&gt;

&lt;p&gt;Most businesses want to keep costs down, but as a rule, hardware is cheap.&amp;nbsp; Developer time is expensive.&amp;nbsp; Don't optimize for the wrong variable.&lt;/p&gt;

&lt;p&gt;If you believe that the First Rule doesn't apply to you, (by the way, you're probably wrong.&amp;nbsp; Go read the first rule again) then it's time to consider the second rule.&lt;br&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;The Second Rule of Code Optimization&lt;/b&gt;: Don't yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Designing code and optimizing code are two very different operations.&amp;nbsp; Your maintenance programmers will thank you not to mix the two.&amp;nbsp; For both optimizing and maintaining code, it is far easier to start from a good solid readable design, than to start from code that was "written optimized". (and that's assuming you can even figure out what the latter was doing).&amp;nbsp; Do not optimize code as you write it, unless you like rewriting over and over.&amp;nbsp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;The Third Rule of Code Optimization&lt;/b&gt;: Profile first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;Optimizing &lt;i&gt;all&lt;/i&gt; of the code is almost never feasible, and is never worth it.&amp;nbsp; It you're going to spend three developer days to squeeze 10 milliseconds of performance out of your code, it's probably better that you get those out of the inner loop of a column lookup, rather than the startup splash screen display code.&amp;nbsp; &lt;/p&gt;

&lt;p&gt;So which code is best to optimize?&amp;nbsp; You don't know.&amp;nbsp; You can generally make educated guesses, but there's your problem.&amp;nbsp; They're just guesses.&amp;nbsp; If you guess wrong (your first guess is almost always wrong), then you'll end up doing more harm than good by optimizing (remember the maintainability hit).&amp;nbsp; So how do you know?&amp;nbsp; Profile.&amp;nbsp; Run tools that will tell you which code is spending most of the time.&amp;nbsp; Optimize that code.&amp;nbsp; Often, you'll find an answer you never expected.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Never optimize without profiling first.&lt;/p&gt;

&lt;hr&gt;
&lt;p&gt;Code optimization is sometimes a necessary evil, but do not forget that it is an evil.&amp;nbsp; It obfuscates the true meaning of the code, and it takes developer time that could be spent on bug fixing or new features.&amp;nbsp; Some applications (such as real-time audio) can't get by without optimizing, but most applications (card games, mail programs, web apps, etc) can get along just fine without unnecessarily complicating the code.&amp;nbsp; And when you do need to optimize, have hard data to back up that you're optimizing the right place.&lt;br&gt;&amp;nbsp;&lt;/p&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3297488" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category></item><item><title>My program is the most important thing on your system, same as all the others.</title><link>http://blogs.msdn.com/audiofool/archive/2006/12/20/my-program-is-the-most-important-thing-on-your-system-same-as-all-the-others.aspx</link><pubDate>Thu, 21 Dec 2006 00:22:41 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1333587</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/1333587.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=1333587</wfw:commentRss><description>&lt;p&gt;Raymond had a really good post yesterday about &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2006/12/19/1325024.aspx"&gt;programs that grab your attention inappropriately&lt;/a&gt;.&amp;nbsp; I recommend reading it.&amp;nbsp; The comments&amp;nbsp;have some&amp;nbsp;good examples of programs, mostly updaters, that take too many liberties.&amp;nbsp; Of course, I completely agree that popping something up in my face completely unrelated to the task I'm performing is among the most annoying things that a computer can do.&lt;/p&gt; &lt;p&gt;So I was reading Raymond's post and nodding to myself over the idea that programs shouldn't be so intrusive.&amp;nbsp; About halfway through, an update dialog popped up on top of the paragraph I was reading.&amp;nbsp; This dialog informed me that Firefox 1.5.0.9 is available to install, and asked me if I'd like to restart Firefox in order to install it.&amp;nbsp; No thanks, I'm kinda busy reading about annoying software.&amp;nbsp; So I click the 'Later' button (Note that updaters in general never give the 'No and stop bothering me' option anymore - I guess too many people clicked it), and am told that I can continue and the update will be applied the next time I restart Firefox.&amp;nbsp; That seems reasonable.&amp;nbsp; So reasonable, in fact, that I wonder &lt;strong&gt;why didn't the updater just do that, instead of interrupting my task?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Ah, some coincidences are just too ironic not to write about.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1333587" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category><category domain="http://blogs.msdn.com/audiofool/archive/tags/Usability/default.aspx">Usability</category></item><item><title>Feature request for the compiler team</title><link>http://blogs.msdn.com/audiofool/archive/2006/12/08/feature-request-for-the-compiler-team.aspx</link><pubDate>Sat, 09 Dec 2006 00:08:22 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1241943</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/1241943.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=1241943</wfw:commentRss><description>&lt;p&gt;I want to preface this by saying that the MS compiler team have worked wonders in improving developer productivity over the years, and can't be thanked enough for&amp;nbsp;turning the C++ language into an enterprise quality platform that has lasted more than a decade.&lt;/p&gt; &lt;p&gt;That said, &lt;strong&gt;"C2259: 'CFoo' : cannot instantiate abstract class&lt;/strong&gt;" is probably one of the least useful of the&amp;nbsp;compiler errors.&amp;nbsp; This error occurs on a line where I am trying to instantiate a CFoo object, and the compiler has&amp;nbsp; determined that CFoo is an abstract class.&amp;nbsp; The problem is&amp;nbsp;that most of the time CFoo isn't supposed to be an abstract class.&amp;nbsp; I'm trying to instantiate it, so chances are good that, semantically, I don't intend CFoo to be an abstract class.&amp;nbsp; The compiler, however,&amp;nbsp;has determined that there is some pure virtual function that isn't overridden, and therefore the class is abstract and cannot be instantiated.&lt;/p&gt; &lt;p&gt;The reason this is a problem is that, in most cases, the bug is not that I'm trying to instantiate the class.&amp;nbsp; The bug is that CFoo hasn't overridden a pure virtual function that needs to be overridden so that CFoo is not abstract.&amp;nbsp; The compiler does a good job of flagging down that there's an error, but it's unhelpful because in most cases, it's flagging down the wrong error.&lt;/p&gt; &lt;p&gt;So what?&amp;nbsp; The compiler can't be expected to discern programmer intent.&amp;nbsp; That's why programmers make the big bucks, right?&amp;nbsp; Lots of error codes are cryptic so why single this one out?&amp;nbsp; Because it's fixable.&amp;nbsp; It's not an unknowable problem.&amp;nbsp; It's just an oversight is all.&amp;nbsp; The answer isn't even technically difficult from a compiler's POV.&amp;nbsp; The compiler has already determined that my class is abstract.&amp;nbsp; It should be easy from there to tell me &lt;em&gt;why&lt;/em&gt; the compiler thinks my class is abstract.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;C2259: 'CFoo' : cannot instantiate abstract class.&amp;nbsp; &lt;font color="#004000"&gt;CFooBase::Bar(int, void*, const char*) is not overridden.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1241943" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category></item><item><title>Honesty as a code metric</title><link>http://blogs.msdn.com/audiofool/archive/2006/11/02/honesty-as-a-code-metric.aspx</link><pubDate>Fri, 03 Nov 2006 06:00:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:937927</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/937927.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=937927</wfw:commentRss><description>&lt;p&gt;Of all of the programmers I've worked with over the years, I can name three who really stick out as the best.&amp;nbsp; These people have earned my respect, and I will &lt;em&gt;always&lt;/em&gt; listen to their opinions, even when I think they're completely off their rockers.&amp;nbsp; I currently have the honor of working with two of those here at Microsoft.&amp;nbsp; The third one I still keep contact with through his blog.&amp;nbsp; &lt;a href="http://chalain.livejournal.com"&gt;Dave Brady&lt;/a&gt; is currently VP of tech at a small Salt Lake City firm, and has&amp;nbsp;a unique&amp;nbsp;insight gained by watching junior coders mature into senior programmers.&lt;/p&gt; &lt;p&gt;Recently, Dave posted an essay entitled &lt;a href="http://chalain.livejournal.com/39332.html"&gt;Dishonest Programming&lt;/a&gt;.&amp;nbsp;&amp;nbsp;The gist of it is something that you'll find in any good coding guide&amp;nbsp;- make sure your identifiers are correct, minimize side-effects, and the like.&amp;nbsp; But I had never really considered "code honesty" as a metric for judging the quality of a piece of code.&amp;nbsp; It's a good read if you're concerned about making sure your code is maintainable.&amp;nbsp; And you &lt;em&gt;should&lt;/em&gt; be.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=937927" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category></item><item><title>If you assume your users are criminals, they will be.</title><link>http://blogs.msdn.com/audiofool/archive/2006/10/25/if-you-assume-your-users-are-criminals-they-will-be.aspx</link><pubDate>Thu, 26 Oct 2006 07:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:875275</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/875275.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=875275</wfw:commentRss><description>&lt;p&gt;A friend recently purchased for me a copy of a game, let's call it "Society III", that he knew I'd like.&amp;nbsp; I had been an avid player of Society and Society II, and Amazon was having a $9.95 special.&amp;nbsp; The game arrived in a standard manufacturer box, with a stamped official-looking CD.&amp;nbsp; It's a legit copy.&lt;/p&gt; &lt;p&gt;Because the game is about two years old by now, there have been a couple of patches.&amp;nbsp; Such is the way of the software lifecycle in the internet age.&amp;nbsp; After installing the game and playing around for a short while, I dutifully went to the publisher's website and downloaded the latest patch.&amp;nbsp; After installing the patch, however, I was no longer able to play the game.&amp;nbsp; Upon launching, I would get a dialog which asked me to "&lt;i&gt;Please insert the Society III CD into drive C:&lt;/i&gt;".&lt;/p&gt; &lt;p&gt;Huh?&lt;/p&gt; &lt;p&gt;Somehow, after the patch, the game has become confused about which drive is the CD-ROM.&amp;nbsp; Obviously, I can't put the disc into drive C:.&amp;nbsp; So I start poking around the config files.&amp;nbsp; Maybe there's a .ini that got corrupted or a registry entry.&amp;nbsp; I do find a line in &lt;i&gt;society3.ini&lt;/i&gt; which lists the install drive, but changing that has no effect.&amp;nbsp; I am unable to convince the game to let me play without inserting a CD into my C: drive.&lt;/p&gt; &lt;p&gt;Now, it turns out, as with most games, that the only reason for the CD at all is to verify that you actually have the original game.&amp;nbsp; No other reason.&amp;nbsp; For performance, the whole game has been copied to the hard drive.&amp;nbsp; As with most games out there, once the game finishes the CD check, the drive goes silent, and I can even safely pop the disc out without affecting game play.&amp;nbsp; So my next course of action is where things get a bit underhanded.&amp;nbsp; I head out to my friendly neighborhood warez website (with my browser security set to maximum, of course), and find a crack for the game which removes the CD check entirely.&amp;nbsp; Just drop in the new, patched .exe, and what do you know, I can play from my hard disk without ever inserting the CD.&lt;/p&gt; &lt;p&gt;So what did we learn from this exercise?&amp;nbsp; Well, first of all, that copy protection software can have bugs too.&amp;nbsp; But unlike innocent glitches, when your software's self-destruct button malfunctions, your UX suffers and users get alienated.&amp;nbsp; My copy of Society III is legitimate, but to use my legitimate copy, I had to resort to shady methods which probably violate the EULA.&amp;nbsp; This game's copy protection software starts from the implicit assumption that the user is a criminal and must be stopped.&amp;nbsp; In this case, thanks to a bug in the software, it turned the user into one.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=875275" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category><category domain="http://blogs.msdn.com/audiofool/archive/tags/Humans/default.aspx">Humans</category></item><item><title>Interface Design and the Law of Leaky Abstractions</title><link>http://blogs.msdn.com/audiofool/archive/2006/09/29/777237.aspx</link><pubDate>Fri, 29 Sep 2006 21:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:777237</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/777237.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=777237</wfw:commentRss><description>&lt;p&gt;Programmers are always trying to make things simpler, usually by making them more complex.&amp;nbsp; Interface too complicated?&amp;nbsp; Need a bit of extra functionality?&amp;nbsp; Want to work closer to the problem?&amp;nbsp; Add a layer of abstraction to the code.&amp;nbsp; As most programmers know, this is, ironically,&amp;nbsp;usually the right solution.&amp;nbsp;&amp;nbsp;Abstraction is critical to breaking a problem down into managable chunks. Of course, as&amp;nbsp;a friend of mine&amp;nbsp;once said, in programming every problem can be solved by adding another layer of abstraction, except for the problem of too much abstraction.&lt;/p&gt; &lt;p&gt;Joel Spolsky once made an important observation about abstractions, which he dubbed the &lt;a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html"&gt;Law of Leaky Abstractions&lt;/a&gt;.&amp;nbsp; As he explains, an abstraction has leaked when a user of the abstraction needs information, data, or knowledge of the underlying implementation or interface.&amp;nbsp; And Spolsky's observation is an inconveniently true one.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Law of Leaky Abstractions:&amp;nbsp; Every non-trivial abstraction leaks.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;So what does this mean if you're designing an interface?&amp;nbsp; You've got some kind of lower-level functionality that you're exposing, so that consumers for your interface can use the functionality of your much simpler interface without regard to the ugly details of the underlying interface.&amp;nbsp; Your new abstraction is so good that nobody will want to use the underlying stuff anymore.&amp;nbsp; In fact, you're so confident in your new interface that you don't need to expose the old one, right?&amp;nbsp; Wrong.&amp;nbsp; Your abstraction will leak.&amp;nbsp; No matter how careful you are&amp;nbsp;in creating the abstraction, there will be a scenario where users of your interface will need knowledge of the underlying implementation or access to the underlying functionality.&amp;nbsp; Your abstraction didn't fail.&amp;nbsp; It just leaked.&amp;nbsp; But if you've hidden the underlying functionality, then you've just disabled every scenario in which a leak occurred.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Corollary to the Law of Leaky Abstractions:&amp;nbsp; An abstraction should not hide or disable&amp;nbsp;that which it abstracts.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This applies to wizards, COM interfaces, API functions, communication protocols, and all other abstractions.&amp;nbsp; I worked on an IRC bot a while back which could take third-party plugins.&amp;nbsp; We abstracted away the IRC protocol into an object-oriented interface that would track channel state information locally and present modes and information through accessors in the interface.&amp;nbsp; We implemented channel.IsModerated to wrap mode 'm',&amp;nbsp;channel.IsTopicLocked to wrap mode 't', and so on with all of the standard modes.&amp;nbsp; We couldn't&amp;nbsp;think of any reason to need the IRC protocol directly, so we didn't expose it.&lt;/p&gt; &lt;p&gt;One network, however, had implemented&amp;nbsp;a custom mode 'U' to block URLs in channel.&amp;nbsp; Obviously we hadn't include an accessor to this mode (we weren't psychic), so our abstraction leaked, and&amp;nbsp;our bot's plugins&amp;nbsp;couldn't use this new mode.&amp;nbsp; The solution was not to add a channel.IsBlockingURLs accessor to our class.&amp;nbsp; That would lead to interface bloat (and a waste of our time) as we have to add a new accessor for each custom one-off mode or protocol extension.&amp;nbsp; No, the solution was to enable plugins to program through our interface and write directly to the protocol, which we did in our next release.&lt;/p&gt; &lt;p&gt;The Law of Leaky Abstractions says that&amp;nbsp;you can never completely abstract away the whole protocol/interface/function/etc.&amp;nbsp; So don't try.&amp;nbsp; Abstractions are still very useful.&amp;nbsp; They make things easier for the 80% case and&amp;nbsp;improve efficiency.&amp;nbsp; But when designing your abstraction, be careful that you don't also disable the 20% case in the process.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=777237" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category></item><item><title>The Dancing Bunnies problem and the need for application-level security</title><link>http://blogs.msdn.com/audiofool/archive/2006/08/18/706708.aspx</link><pubDate>Sat, 19 Aug 2006 01:59:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:706708</guid><dc:creator>RyanBemrose</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/audiofool/comments/706708.aspx</comments><wfw:commentRss>http://blogs.msdn.com/audiofool/commentrss.aspx?PostID=706708</wfw:commentRss><description>&lt;p&gt;&lt;a href="http://blogs.msdn.com/oldnewthing/"&gt;Raymond&lt;/a&gt; today has a &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2006/08/18/705957.aspx"&gt;discussion&lt;/a&gt; up about the folly of trying to set security with a granularity of per-DLL.&amp;nbsp; As&amp;nbsp;he explains, the moment you let something untrusted run in your process space, you cannot trust anything in the process.&amp;nbsp; You cannot wall off a DLL or a section of code from the rest of the process.&amp;nbsp; "That's why code is not a security principal," he concludes.&lt;/p&gt; &lt;p&gt;But you &lt;em&gt;can&lt;/em&gt; wall off a process.&amp;nbsp; There is an ACL associated with each running process (via its user context), so you &lt;em&gt;can&lt;/em&gt; restrict what code can do depending on its process.&amp;nbsp; More on that in a moment.&lt;/p&gt; &lt;p&gt;The other point&amp;nbsp;Raymond drives home is that, to the system, there is no difference between the application and the user.&amp;nbsp; Put another way, When an application has the credentials of a user and attempts to perform an operation, there is no good way for the system to know&amp;nbsp;whether&amp;nbsp;the app &lt;em&gt;asked the user&lt;/em&gt; before performing it.&amp;nbsp; Therefore, the only effective way to limit what an application can do is reduce its process ACL &lt;em&gt;when the application is launched&lt;/em&gt;, and then limit what it can do based on that.&lt;/p&gt; &lt;p&gt;So consider this in the context of the &lt;a href="http://blogs.msdn.com/larryosterman/archive/2005/07/12/438284.aspx"&gt;Dancing Bunnies problem&lt;/a&gt;.&amp;nbsp; There is a website which will let me download an executable to&amp;nbsp;watch dancing bunnies.&amp;nbsp; Conventional security wisdom says that the only way to be secure is to not download the executable.&amp;nbsp; This is obviously the most secure choice, from a technical standpoint, but the technical standpoint&amp;nbsp;goes on its ear when you add&amp;nbsp;a user to the equation.&amp;nbsp; Conventional security wisdom doesn't let me see my dancing bunnies, so I'm going to download it anyway.&amp;nbsp; When I run the executable, it takes on my user token, and suddenly the website's code has the full ability to do anything to my system that I can do -- and if I'm on a pre-Vista OS, that means admin access.&amp;nbsp; What's worse, it probably won't even bother to ask whether I want my system owned.&amp;nbsp; The nerve!&lt;/p&gt; &lt;p&gt;So somehow we&amp;nbsp;lost the most secure option (not downloading the exe) because it wasn't&amp;nbsp;acceptible to the user -- I couldn't see my dancing bunnies.&amp;nbsp; Without that most secure option, the only one left&amp;nbsp;is the least secure (system owned).&amp;nbsp; What I think we need is another status for the app.&amp;nbsp; I want an execution option that says "I want to see my dancing bunnies, but I don't want my system owned".&amp;nbsp; UAC on Vista does a very good job of preventing the system owned result, but a malicious program can still do a lot of damage.&amp;nbsp; Even better is the "low" security context that IE7 runs in by default on Vista, which can only access certain directories and APIs.&amp;nbsp; This mode is effectively the application-level security that I spoke of earlier.&lt;/p&gt; &lt;p&gt;What I'd like to see, as a partial answer to the Dancing Bunnies problem,&amp;nbsp;is the ability to download and save an app from the internet, and have that app marked as "untrusted".&amp;nbsp; When I launch the app, it launches in some sort of sandbox similar to the "low" security mode with restricted process permissions.&amp;nbsp; If&amp;nbsp;it's coded correctly then it shows me my dancing bunnies.&amp;nbsp; If it's malicious, then I haven't lost anything.&amp;nbsp; This is something that users will buy into.&lt;/p&gt; &lt;p&gt;Of course, we still have the social engineering problem of exes that tell the user they can only see dancing bunnies after they click away that nagging UAC prompt.&amp;nbsp; The way to fix that is to convince them that Microsoft is more trustworthy than Ye Olde Maliciouse Website.&amp;nbsp; When I come up with the solution to that one, I'll let you know.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=706708" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/audiofool/archive/tags/Programming/default.aspx">Programming</category><category domain="http://blogs.msdn.com/audiofool/archive/tags/Windows/default.aspx">Windows</category></item></channel></rss>