<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1747662717669511114</id><updated>2012-01-31T14:44:47.147-08:00</updated><category term='story'/><category term='design'/><category term='idea'/><category term='digital book'/><category term='coffeescript'/><category term='overengineering'/><category term='software development'/><title type='text'>Bill Yang's Weblog</title><subtitle type='html'>Sharing my thoughts on software development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.billyang.me/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-1350897644846932286</id><published>2012-01-09T14:23:00.000-08:00</published><updated>2012-01-09T14:23:05.259-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>The simple and yet complex case of KISS</title><content type='html'>I was blown away when first introduced to &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt;. At the time, I was frustrated with how overly complicated our enterprise software was designed. It was a rewrite of a legacy system and our architect single-handedly wrote a custom framework on top of ASP.NET MVC framework, with the goal to make it more succinct and extensible.&lt;br /&gt;&lt;br /&gt;The only problem, was that everybody was so confused about how it worked, that we lined up to the door of the architect with questions on how to implement particular logic. I carried that bitter taste of over-engineering for a long time, and have rigorously asked myself every time I make any design decisions, if my design was not simple enough...until now.&lt;br /&gt;&lt;br /&gt;Today, a very smart and capable colleague criticized a simple piece of my code for being over-engineered, it was a surprise.The problem was fairly simple, so I skipped over things like IoC container, unit testing and the like, implementing only a very simple MVC design, with model layer logic located in separate project, using a single-class Micro ORM (PetaPoco) as opposed to a full-blown ORM.&lt;br /&gt;&lt;br /&gt;In my mind, things cannot get simpler than this. Well, technically it can, like skipping the overhead of unit-testability, keeping all logic within single project, using built-in SqlDataReader instead of Micro ORM. However those measures only reduces complexity marginally, while making future refactoring exponentially more difficult. In my book, those are bad trade offs.&lt;br /&gt;&lt;br /&gt;What I failed to recognize was that, you see, I have been writing code this way for many projects by now and all those concepts and code structures are intuitive to me. Writing and reading code structured this way is as straight-forward to me as code structured in the simplest possible way (TM).&lt;br /&gt;&lt;br /&gt;This was not the case for my colleague.&lt;br /&gt;&lt;br /&gt;He has different background than I do, and has grown different habits. All the "intuitive" project structure, the MicroORM, and unit testable code was extra complexity to him. While he recognizes the value of all those things, those are extra complexity that has no potential return due to simplicity of the project.&lt;br /&gt;&lt;br /&gt;In the end, after some discussion with him and mental struggle with myself, I got rid of most of the "fluffy" stuff. I also lost the bitter taste for the "over-engineering" architect, after all, that whole framework is probably quite intuitive to him.&lt;br /&gt;&lt;br /&gt;Lesson learned: Simplicity, like anything, is subjective -- what is simple to one person may not be the same for another. And when working in a team, you have to consider the whole team when making design decisions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-1350897644846932286?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/1350897644846932286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2012/01/simple-and-yet-complex-case-of-kiss.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1350897644846932286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1350897644846932286'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2012/01/simple-and-yet-complex-case-of-kiss.html' title='The simple and yet complex case of KISS'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-8991559090419658014</id><published>2011-07-29T16:53:00.000-07:00</published><updated>2011-07-29T16:55:21.691-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Visual Studio Website Project vs Web Application Project</title><content type='html'>There probably has been billions of articles written about this topic, and I am no expert who understands the full extent on how the two types of project differ from each other. However, most of those articles are fairly old, and the year 2011 deserves a new article about this topic. :)&lt;br /&gt;&lt;br /&gt;So if you are a developer working in a Microsoft shop, chances are you would use at least one of the following: ASP.NET MVC, NuGet, Unity Application Block, Unit Test, Gated Check-in, custom build event/script.&lt;br /&gt;&lt;br /&gt;If you use any of those consistently in your projects, it's probably best to stick with Web Application Project, some of them (i.e. ASP.NET MVC) flat out cannot work with Website Project; some would, but requires non-typical setup which you have to investigate and assess.&lt;br /&gt;&lt;br /&gt;Conclusion: in year 2011, if you are not sure, use Web Application Project.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-8991559090419658014?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/8991559090419658014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2011/07/visual-studio-website-project-vs-web.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/8991559090419658014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/8991559090419658014'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2011/07/visual-studio-website-project-vs-web.html' title='Visual Studio Website Project vs Web Application Project'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-1123824462792027149</id><published>2011-07-28T22:59:00.000-07:00</published><updated>2011-07-29T16:54:58.277-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coffeescript'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>CoffeeScript global variable and @ keyword</title><content type='html'>I finally managed to pick up CoffeeScript, by writing a small game using CoffeeScript and Canvas. Writing code with CoffeeScript is a very fluent experience, even though I have never used Ruby and have C# background, the syntax feels so natural and code enjoyable to write.&amp;nbsp;All the good things aside, I also got caught by a little gotcha of the language.&lt;br /&gt;&lt;br /&gt;In the world of CoffeeScript, global variables must be explicitly declared, using either @ or window keyword, and most tutorials recommend @ due to its succinctness:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@luckyNumber = 4&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;this attaches luckyNumber into window object and thus accessible globally. The tricky thing is if you do the same declaration in a class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class MyClass&lt;br /&gt;  constructor: (@luckyNumber = 5) -&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;all of sudden, @luckyNumber becomes a property of MyClass, and is not attached to the window object anymore! Now consider following situation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@luckyNumber = 4&lt;br /&gt;class MyClass &lt;br /&gt;  constructor: (@luckyNumber = 5) -&amp;gt;&lt;br /&gt;&lt;br /&gt;  showLuckyNumber: () -&amp;gt;&lt;br /&gt;    alert(@luckyNumber)&lt;br /&gt;&lt;br /&gt;(new MyClass).showLuckyNumber()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Is it going to give you 4 or 5? ... Yes you probably guessed right, it's 5. To access the global variable, you need:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;showLuckyNumber: () -&amp;gt;&lt;br /&gt;    alert(window.luckyNumber)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;While tricky, this is not exactly a CoffeeScript problem, but weirdness inherited from Javascript. Remember the golden rule&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;:&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;&lt;i&gt;"It's just JavaScript"&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'Helvetica Neue', 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-1123824462792027149?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/1123824462792027149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2011/07/coffeescript-global-variable-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1123824462792027149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1123824462792027149'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2011/07/coffeescript-global-variable-and.html' title='CoffeeScript global variable and @ keyword'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-701940037059098623</id><published>2010-09-15T20:32:00.000-07:00</published><updated>2010-10-05T20:10:16.855-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>A redemption of Waterfall model</title><content type='html'>It is almost common knowledge now that waterfall model does not work, especially if you talk to programmers leaning to the agile persuasion. &amp;nbsp;In this article I am going to give waterfall model its deserved credit, and to look at software development from a different perspective.&lt;br /&gt;&lt;br /&gt;Before start, I need to first make a disclaimer -- I am not talking about "strict" waterfall or "strict" agile, I don't think those extreme cases apply to most real life situations.To me, any development processes that falls into defining clear phases (initiation, analysis, design, development, testing) are using waterfall model, regardless compromises made to&amp;nbsp;accommodate&amp;nbsp;different circumstances.&lt;br /&gt;&lt;br /&gt;First, let's talk a little about history. Waterfall model originated from manufacturing and construction industries, the waterfall model does not only suits the limitation of the projects of those industries (where flexibility is impossible when real goods are involved), but also suits their management method --&amp;nbsp;&lt;a href="http://www.joelonsoftware.com/items/2006/08/08.html"&gt;The Command and Control Management Method&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If a company using command and control management method tries to use agile development model, guess what will happen? Well, agile practices rely heavily on making constant changes based on new discoveries and shifting requirements which will need to travel back to the top and come back down to the developers. When too many changes are pending, the decision maker becomes a bottleneck while the developers are held up until a decision can be made. This does not only creates more pressure on the decision maker but also would actually delay the project delivery.&lt;br /&gt;&lt;br /&gt;On the other hand, waterfall model tends to minimize the communication requirement between decision maker and developers. When the project is in analysis/design phase, developers can be given other tasks like maintaining existing projects. Once the construction starts, developers are called in and start doing the work. There will be only occasional cases when changes are needed AND possible, giving the decision maker plenty leisure to examine issues popping up without delaying the project much.&lt;br /&gt;&lt;br /&gt;Of course, the better solution would be to change the management process to be more decentralized to avoid decision making bottleneck. But unfortunately, real life situations are normally far from ideal. Maybe there aren't enough competent developers to delegate responsibilities to (and no, you don't want to set everybody lose to wreck havoc to the code base); or the company has been burnt by having too many fingers making decisions; or the business model can tolerate low quality software thus improving the development process is &amp;nbsp;lower priority; or maybe simply just because.&lt;br /&gt;&lt;br /&gt;You have to really think hard about the situation before applying any best practices or the hottest methodologies. Sometimes you may have to make compromises and take the second-best option.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-701940037059098623?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/701940037059098623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2010/09/redemption-of-waterfall-model.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/701940037059098623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/701940037059098623'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2010/09/redemption-of-waterfall-model.html' title='A redemption of Waterfall model'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-3321597631238856832</id><published>2010-08-09T20:43:00.000-07:00</published><updated>2010-08-09T20:50:13.983-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='overengineering'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Premature Abstraction</title><content type='html'>Everyone knows that premature optimization is root of all evil and in extreme cases the programmer who does such thing will be stoned to death.&lt;br /&gt;&lt;br /&gt;But not many people seem to be bothered with premature abstraction, or encapsulation or whatever people fancy it. Here is what I mean by premature abstraction: creating a train of complex framework to perform simple tasks to make them future proof.&lt;br /&gt;&lt;br /&gt;This is a natural tendency after becoming more and more fluent in OO design, as one of the main advantage of OO is abstraction, to make code reusable and extensible. But like making a dish, if you put in too much of any sauce, it will ruin the taste. Abstraction is no exception.&lt;br /&gt;&lt;br /&gt;Here is what will actually happen when you design something to be "future-proof": most of the anticipated requirements will be forgotten, and many new ones will show up from no where and on things you never thought of. When such thing happens, it'll be a painful experience to refactor that neatly designed and implemented framework to accommodate new requirements. If the project happen to be behind schedule at the time, which is always, guess what, you may not get the leisure and time to refactor the framework and hacks/workarounds will be applied to make it even harder to refactor. In fact once enough duct-tape is being applied to that originally neatly designed framework, nobody will dare to touch it any more. &lt;br /&gt;&lt;br /&gt;Now I think about it, there is actually a proper name for it: it is called &lt;b&gt;over-engineering&lt;/b&gt;. And it is quickly surpassing premature optimization to become the new root of all evil.&lt;br /&gt;&lt;br /&gt;I will stone you next time I see you do that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-3321597631238856832?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/3321597631238856832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2010/08/premature-abstraction.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/3321597631238856832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/3321597631238856832'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2010/08/premature-abstraction.html' title='Premature Abstraction'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-2247250386510662197</id><published>2010-03-05T20:45:00.000-08:00</published><updated>2010-03-09T20:29:46.402-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='idea'/><category scheme='http://www.blogger.com/atom/ns#' term='digital book'/><title type='text'>You don't need a publisher</title><content type='html'>I was talking to my imaginative friend Joe the other day, trying to figure out why there still hasn't been a good website to read novels. We were talking about why book publishers should release books online in this era of Internet, and it struck me, why was publishers needed in the first place?&lt;br /&gt;&lt;br /&gt;Back in the days, book publishing was a huge task and no small entities (a.k.a. authors) can do it for themselves, and in order to reach a wider audience without devoting their life to marketing which many may not be good at, book publishers were necessary.In fact things haven't changed much since! Book publishing is still a tremendous effort, you have to get editors to review the book, get advertisers to market the book, get designers to do book design, get printing companies to print the book, then go through a chain of distribution to get the books to readers.&lt;br /&gt;&lt;br /&gt;And the result of that? Authors don't make that much. According to this &lt;a href="http://www.genreality.net/the-reality-of-a-times-bestseller"&gt;post from a New York Times best selling author&lt;/a&gt;, she made a staggering $24,517.36 on a book that sold for 61,663 copies, about 40 cents for every book that's sold for $7.99 at retail. That's very little, but considering the amount of work the publisher has to do, it is only fair. Or is it?&lt;br /&gt;&lt;br /&gt;In a business partnership, each partner has to contribute value to the business and take his/her share of profit based on the contribution, it is not always easily measurable, but mostly fair or the partnership won't work. Let's take a look what publisher brings to the table, that warrant a 95% cut [1].&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Editor Review&lt;/b&gt;&lt;br /&gt;Editors are quite helpful as they check for spelling, grammar and logical errors,they also give some good advices to improve the book or edit it directly. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Marketing&lt;/b&gt;&lt;br /&gt;While authors can do a lot of the marketing themselves (and are increasingly required to), paid marketing campaign and advertisement still have their values. After all, who don't want to sell a few more books?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Printing and Distribution&lt;/b&gt;&lt;br /&gt;These are normally done by separate companies. Printing and distribution is a lot of work, and book shelves are costly.&lt;br /&gt;&lt;br /&gt;Publishers are indeed bringing a lot to the table in traditional publishing practice to warrant their share of profit. But things has changed! Advance in computer technology and the Internet has made a lot of things obsolete, including publishers, and here is why:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Editor Review&lt;/b&gt;&lt;br /&gt;&amp;nbsp;Spell checkers will weed out most of the typos and simple errors. Some helpful readers or a fellow author could definitely be able to help to do the proofreading to find any logical errors. In fact the readers will feel delighted to have a sneak peek into your newest book, it's a privilege! And even if errors manage to loom into your book, you can always go back and fix it, a luxury you don't have with paper backs.&lt;br /&gt;&lt;br /&gt;And what beats reader feedback on how to improve your book? After all, the definition of a good book is that people like it enough that they will buy it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Marketing&lt;/b&gt;&lt;br /&gt;&amp;nbsp;Authors already do a lot of marketing these days, and with the help of Internet, self-promotion has not been easier! If you really think you need some professional marketing, no one can stop you from hiring a marketing company, and you get to decide whether that's worth it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Printing and Distribution&lt;/b&gt;&lt;br /&gt;&amp;nbsp;Need to say no more, distributing books online cost a fraction of traditional printing and distribution model. And there is always print-on-demand option for readers who prefer paperback.&lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Notes:&lt;br /&gt;[1] To publishers' defense, they do not take 95% of the sales, money goes to all parties involved in the process of publishing a book. But to an author, it doesn't make a difference where the money went.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-2247250386510662197?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/2247250386510662197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2010/03/you-did-not-need-your-publisher.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/2247250386510662197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/2247250386510662197'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2010/03/you-did-not-need-your-publisher.html' title='You don&apos;t need a publisher'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-2738596633925996843</id><published>2010-02-28T12:34:00.000-08:00</published><updated>2010-09-22T14:00:33.364-07:00</updated><title type='text'>Google AI Challenge</title><content type='html'>I have recently competed in &lt;a href="http://csclub.uwaterloo.ca/contest/"&gt;Google AI Challenge&lt;/a&gt;, it was a lot of fun and I have learned quite a few things. Here is a quick explanation of the strategy I employ.&lt;br /&gt;&lt;br /&gt;First it checks to see if two bots are seperated.&lt;br /&gt;If two bots are connected, it will use Minimax/Alpha Beta Pruning to determine the best move it should take. The evaluation functions is as follows:&lt;br /&gt;&amp;nbsp; 1, if I win: +1000; opponent wins: -1000&lt;br /&gt;&amp;nbsp; 2, if disconnected, and I have more open spots: +800; opponent has more open spots: -800; same: 0; Open spots is determined by flood fill.&lt;br /&gt;&amp;nbsp; 3, if still connected,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; find articulation points and divide map into zones&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; find the largest zones&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; use breadth first algorithm to divide the zones into spots I can reach first&lt;spots closer="" me="" to=""&gt;&amp;nbsp;and spots enemy can reach first&lt;spots closer="" opponent="" to=""&gt;&lt;/spots&gt;&lt;/spots&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return final score as &lt;i&gt;spots I can reach first&lt;/i&gt; - &lt;i&gt;spots enemy can reach first&lt;/i&gt;&lt;br /&gt;The whole Alpha Beta Pruning process is wrapped using a Iterative Deepening loop.&lt;br /&gt;&lt;br /&gt;When two bots are seperated, simply use a breadth first algorithm to determine how many open spots are left after each move using flood fill. Then choose the move that leaves the most spots open, in case two moves are equally good, hug the wall.&lt;br /&gt;&lt;br /&gt;It is written in C#, and can be found here: &lt;a href="http://github.com/analyst74/Tron-Bot"&gt;http://github.com/analyst74/Tron-Bot&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&amp;nbsp;&lt;/b&gt; here is a great write up about the challenge and many related links &lt;a href="http://www.benzedrine.cx/tron/"&gt;http://www.benzedrine.cx/tron/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-2738596633925996843?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/2738596633925996843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2010/02/google-ai-challenge.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/2738596633925996843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/2738596633925996843'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2010/02/google-ai-challenge.html' title='Google AI Challenge'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-3618259242059205219</id><published>2010-01-21T22:19:00.000-08:00</published><updated>2010-01-21T22:19:52.125-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='story'/><title type='text'>on Google vs China</title><content type='html'>Now the immediate heat of discussion on Google's &lt;a href="http://googleblog.blogspot.com/2010/01/new-approach-to-china.html"&gt;new approach to China&lt;/a&gt; has settled a little (until new news come out from either party).&lt;br /&gt;&lt;br /&gt;A lot of interesting analysis and speculations have emerged from the blogsphere and news medias, from bashing China's (if you don't know yet) human rights problem to questioning Google's real motives. You can find them all &lt;a href="http://blogsearch.google.ca/blogsearch?q=google%20china&amp;amp;oe=utf-8&amp;amp;rls=org.mozilla:en-US:official&amp;amp;client=firefox-a&amp;amp;um=1&amp;amp;ie=UTF-8&amp;amp;sa=N&amp;amp;hl=en&amp;amp;tab=wb"&gt;here&lt;/a&gt; (courtesy to Google!).&lt;br /&gt;&lt;br /&gt;One thing everyone agrees, is that this is a significant event, but how significant? Will it change the world?&lt;br /&gt;&lt;br /&gt;Fast forward forty years.&lt;br /&gt;&lt;br /&gt;It's year 2050, we have just achieved 80% CO2 reduction goal set out forty years ago thanks to innovations in energy sector. On the news:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;(Yahoo News) A syndicate of Internet companies lead by prominent companies like Google, Microsoft and eBay, have threatened to blacklist Australia if a new tax is implemented. The tax will be applied to companies who do not voluntarily comply with its censoring rules, and cover costs associated with censoring on the ISP level. Rumors say proponents of the tax are rapidly losing support from voters for fears that those threats become real. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;blockquote&gt;(Apple Daily) In a bold move to tackle lumping economy and increasing domestic unrest, Japanese government has announced a plan to lift regulations related to the Internet, citing "The Internet has sovereignty of its own and cannot be governed in traditional means". The plan includes establishing a governing entity called UN (United Netizens) and handing over all regulatory duties to this entity. UN council body will consist representatives from prominent Internet companies and user groups. Japan urges other countries to follow the "great leap forward in net-neutrality". Economic analysts say such move could attracts over 5 trillion foreign investment to flow to Japan, especially from countries with complex or repressive Internet laws like US and China.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;How does this future sound?&lt;br /&gt;&lt;br /&gt;Maybe, just maybe, one day the Internet could be free.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-3618259242059205219?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/3618259242059205219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2010/01/on-google-vs-china.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/3618259242059205219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/3618259242059205219'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2010/01/on-google-vs-china.html' title='on Google vs China'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-7933020541695026214</id><published>2009-12-06T16:10:00.000-08:00</published><updated>2009-12-06T16:10:52.952-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='story'/><title type='text'>Two management styles</title><content type='html'>There are two brilliant managers called Jack and Gordon.&lt;br /&gt;&lt;br /&gt;They both work for the same company -- it's one of the nation's biggest corporation and has huge influence in the market. Having a job in the company is considered a privilege, let alone a managerial position. One has to be cream of the most brilliant crop to get there.&lt;br /&gt;&lt;br /&gt;Jack is a very smart man, and he has gained substantial experience in this field to make him a distinguished expert in the company. This is not to say he lacks social skills though. In fact people admit that he posses both technical expertise and some political talent. He is a star leading a team of experts solving some of the company's most difficult problems. His talent is both widely appreciated by the senior management and admired by fellow employees, even those who are not in his team.&lt;br /&gt;&lt;br /&gt;Gordon is also a very smart man, although not quite as sharp as Jack is. He is considered by most people to be a people's manager as compared to Jack, who is both a remarkable manager AND technical leader. Gordon's team is also one of the most successful teams in the company, the product they created has received outstanding reception and is bringing the company a steady stream of income measured in the millions. The success of Gordon, as people say, is widely contributed to the great idea (which did not come up by himself) and a superb team he got stuck with. His team is indeed superb, many of them have proved themselves to be A players and there is one young guy who is considered to be a wizard even among his team of A players, a star employee he is. Anyone who is lucky enough to stuck with a good idea and a superb team like Gordon's would have succeeded, probably more wildly than Gordon have.&lt;br /&gt;&lt;br /&gt;Fast forward fifteen years.&lt;br /&gt;&lt;br /&gt;Jack has gotten old and has stepped away from the company's core team since he lost his sharpness a while ago. The company still treats him well though, and he is enjoying his life with a much less stressful job. He misses the glory days, but nobody can fight time, his time has passed.&lt;br /&gt;&lt;br /&gt;Gordon has lost the best members of his original team, three of them including the star employee were promoted "past" him, others eventually left and got promotion in other companies. But the team somehow managed to survive, he always seem to be lucky to recruit a few remarkable employees who kept the team and Gordon himself afloat, until about five years ago when he was promoted to senior management. "It is all due to his political talent", some people say.&lt;br /&gt;&lt;br /&gt;But the company's chief architect disagrees:"He (Gordon) is the best manager I've ever met and the time working for him was the best of my career. He did not only understand both the business and technical sides, shielded us from senior management pressure, but also cared for us personally. He fought tooth and nails with HR to give us bigger raises and single handedly convinced senior management to promote me to the architect team. Without him, I wouldn't have been where I am now. I am so glad that I am reporting to him again."&lt;br /&gt;&lt;br /&gt;The chief architect was not the only one Gordon promoted -- almost a dozen of the company's current managers used to work in Gordon's team and have since been recognized and promoted. They were equally thankful for the chance to work for Gordon. On the other hand, nobody seems to remember Jack except a few old timers, and Jack has never been "lucky" enough to recruit such talented people like Gordon has. Those "B players" who worked for him have either stayed where they were or have since left the company.&lt;br /&gt;&lt;br /&gt;"Luck" is really important, as people say.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-7933020541695026214?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/7933020541695026214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2009/12/two-management-styles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/7933020541695026214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/7933020541695026214'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2009/12/two-management-styles.html' title='Two management styles'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-140269335999505186</id><published>2009-11-09T20:24:00.000-08:00</published><updated>2009-11-09T20:24:32.830-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Does Inheritance breaks Encapsulation?</title><content type='html'>&lt;blockquote&gt;Because inheritance exposes a subclass to details of its parent's implementation, it's often said that 'inheritance breaks encapsulation' (&lt;a class="mw-redirect" href="http://en.wikipedia.org/wiki/Gang_of_Four_%28software%29" title="Gang of Four (software)"&gt;Gang of Four&lt;/a&gt; 1995:19)&lt;br /&gt;&lt;/blockquote&gt;No I did not read the GoF book, I'm quoting them because I believe quoting important people makes my point more correct.&lt;br /&gt;&lt;br /&gt;So we know that inheritance breaks encapsulation because it exposes a subclass to details of its parent's implementation. But what is the harm of exposing parent's implementation to subclasses? Why does it matter?&lt;br /&gt;&lt;br /&gt;Imagine this situation: you are coding a very core class for a system, and decided to make a field protected so it's convenient for subclasses to access it. After all, it is a core member field that all subclasses need to use and declaring it as protected seemed like reasonable thing to do. Everything worked fine and smoothly in the beginning. Then 5 years passed, assuming the system is actually making money for your company, it has grown substantially through a steady stream of feature requests. And many subclasses were created inheriting the core class you wrote. Now imagine you have to change that protected field, and *bam*, you're stuck! Because there are many subclasses sprang across many assemblies, and nobody has a headcount of them all! So you either end up not changing it, or do the change and fix as many subclasses as possible, then prey you don't miss any.&lt;br /&gt;&lt;br /&gt;Does this sound familiar? Yes, this is the exact scenario when someone accidentally declared a field public for convenience when it should have been properly encapsulated, I hope it's not you, oops! (I'll be honest, I did this before!)&lt;br /&gt;&lt;br /&gt;I believe this is the context when those influential people declared that inheritance breaks encapsulation. But a class does not have to expose its implementation to subclasses, take &lt;a href="http://msdn.microsoft.com/en-us/library/system.collections.hashtable%28VS.80%29.aspx"&gt;Hashtable&lt;/a&gt; for example: it is carefully designed to hide all implementation details from not just the rest of the world, but also its subclasses. So if there is a change to the default hashing method, how data is stored internally or any of the implementation details, all the subclasses created by developers across the world will not be broken! I believe a more proper statement would be:&lt;br /&gt;&lt;blockquote&gt;Overusing protected members breaks encapsulation.&lt;br /&gt;&lt;/blockquote&gt;And the remedy to that? Don't overuse the protected keyword. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-140269335999505186?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/140269335999505186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2009/11/does-inheritance-breaks-encapsulation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/140269335999505186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/140269335999505186'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2009/11/does-inheritance-breaks-encapsulation.html' title='Does Inheritance breaks Encapsulation?'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1747662717669511114.post-1632881907482053584</id><published>2009-10-12T14:33:00.000-07:00</published><updated>2009-11-18T22:19:54.119-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>The problem of too many layers of indirection (abstraction)</title><content type='html'>So everyone has probably heard this by now&lt;br /&gt;&lt;blockquote&gt;All problems in computer science can be solved by another level of indirection&lt;strike&gt; &lt;/strike&gt;&lt;br /&gt;&lt;/blockquote&gt;and the corollary&lt;br /&gt;&lt;blockquote&gt;...except for the problem of too many layers of indirection&lt;br /&gt;&lt;/blockquote&gt;While it sounds smart and witty, I have never quite figured out what the corollary is referring to. After all, our society is built based on layers and layers of &lt;strike&gt;indirection&lt;/strike&gt; abstraction, and that's how we advanced into modern society. It is a proven concept.&lt;br /&gt;&lt;br /&gt;Well, let me step back a little and talk about an interesting issue I had recently. It was decided that our enterprise contract management software is not responsive enough and a few engineers were tasked to take a look at the problem.&lt;br /&gt;&lt;br /&gt;Thanks to the advancement of software development, we now have awesome tools like dotTrace, among others, to simplify the daunting task of inserting time stamping instructions into every single method in the application. Looking at the profiling result, an interesting method quickly grabbed my attention -- it is a heavy lifter which makes up 40% of the overall page load time. Upon closer investigation, I realized that it is our new navigation tree which loads a gigantic metadata file that contains all information there is to know (like data dependency, context relation, data validation rule, permission rule and etc). To be more specific:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;it was reloading the (static) data every page load.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;only a small amount of data (those related to current page) is actually required.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;it was executed twice on every page load.&lt;/li&gt;&lt;/ol&gt;Let's forget about the first two, and focus on the third problem. How did this happen? I mean, this looks like a simple problem that even junior programmers would know to avoid.&lt;br /&gt;Well, the truth is, the original developer implemented the navigation module nicely, with caching and stuff, so the heavy-lifting method will never be called twice. Then a few months later, someone had to fix a caching bug -- the cached navigation tree became corrupted for some unknown reason. He looked around, and found a little method that was nicely packed and seems harmless, which will solve his problem by rebuilding the corrupted data. It was a perfectly logical choice on his side, although little did he know that about 3 abstraction layers down the road, it reads a gigantic xml file and create a few hundred objects on the fly.&lt;br /&gt;&lt;br /&gt;Maybe the original developer should have documented this code better, maybe the other developer should have been more cautious when using other people's code. But the real issue is, abstraction hides so much detail that gives you a false sense of confidence. It makes you believe you know everything, after all, the method name and comment will be sufficient to describe what it does right? (hint, no) If it does, it would have to explain what all its function calls do, and the functions called by those functions it calls, and the functions called by those functions called by those functions it calls...&lt;br /&gt;&lt;br /&gt;Every abstraction layer does not only adds a little over head to the CPU, but also to the poor human who has to read that code. Be careful, those little overheads may come and bite you one day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1747662717669511114-1632881907482053584?l=blog.billyang.me' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.billyang.me/feeds/1632881907482053584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.billyang.me/2009/10/dark-side-of-abstraction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1632881907482053584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1747662717669511114/posts/default/1632881907482053584'/><link rel='alternate' type='text/html' href='http://blog.billyang.me/2009/10/dark-side-of-abstraction.html' title='The problem of too many layers of indirection (abstraction)'/><author><name>Bill Yang</name><uri>http://www.blogger.com/profile/11095977392691545904</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
