how do you manage complexity (2)

來源: 1sthiker 2014-11-07 20:11:58 [] [博客] [舊帖] [給我悄悄話] 本文已被閱讀: 次 (5594 bytes)
Our elevator announces the direction it's going after the floor number. It says, "8th floor, going up", or "8th floor, going down". One day, however, it simply said, "8th floor". Nothing else. I waited, nothing. Waited some more, still nothing. Until I walked away.
>You might laugh if the elevator says "8th floor, going nowhere". But it does make some sense. It eliminates uncertainty. It leaves no surprise. Most importantly, it turns an exception into a normal case.

Exceptions are a major source of complexity. Many years ago, I realized that most code are there to handle special cases. You struggle through 30 lines of code trying to figure out what a function does, only to find the answer in the last 2 lines, which calls another function. Look at this code:


private void ProcessLine(string line, IList result) {
     if (isBlank(line))
        return;
     if (isComment(line))
        return;
     string typeCode = GetTypeCode(line);
     IReaderStrategy strategy = (IReaderStrategy)_strategies[typeCode];
     if (null == strategy)
        throw new Exception("Unable to find strategy");
     result.Add(strategy.Process(line));
} 

Exceptions are also a major source of bugs. You could forget to check for zero, or get lost in a maze of if-then-else. Even if you don't, people who maintain your code will certainly do.

One obvious way to deal with exceptions is to turn them into normal cases. A good example is "8th floor, going nowhere". Another example is a Null class which simply does nothing. Experienced programmers return an empty list instead of a null, for the same reason. The above code could be simplified greatly if we have a CommentStrategy, a NullStrategy:


private void ProcessLine(string line, IList result) {
     string typeCode = GetTypeCode(line);
     IReaderStrategy strategy = (IReaderStrategy)_strategies[typeCode];
     result.Add(strategy.Process(line));
}

Many design patterns have the same goal. The Adapter pattern turns a special case into a normal case. The Composite pattern makes a group of objects to behave like a single object.

In my trading application, the user can take the same action on multiple accounts. The obvious way is to check each action to see if it's meant for multiple accounts. If so, loop through the accounts and do the action.

However, this would mean to write the same code in at least a dozen places. Using the Composite pattern, I wrote a ComboBroker class which works on multiple accounts but implements the same interface as a single account Broker. This removes the special case from client code. Moreover, the ComboBroker can implement complicated allocation logic which would be extremely messy if you have to do it in a dozen places.

Another way to deal with exceptions is to divide and conquer. In my first job, I had a chunk of Visual C++ code which draws stock charts. It was buggy. I fixed it a few times but sooner or later, a new problem would come up. I had a lot of if-then-else logic there to paint the screen in different ways for different charts and different user preferences. After a lot of frustration, I broke the chunk of code into several classes, each handling only one special case. Each class is single minded. No more if-then-else. And the bugs never came back. Incidentally, this is a Design Pattern, called Strategy.


A third way to deal with exceptions is to externalize them. I once had to fix a Unix script which calls many subscripts only available in production. I had to make many changes just to get it to run in development environment. This messed up the script. Moreover, I had to make sure to reverse all these changes before checking the code back into production, with no way to finally test it. It was very risky. The environmental exceptions not only got into my code, they also got into my process.

My solution was to create a fake production environment with fake scripts. Without touching the master script, I got it to run in development. All changes I made to it were meant for production, not for dealing with environmental exceptions. And most importantly, it went into production unchanged after a successful test run.


Exceptions are not only bad for software, they're also bad in our every day lives. One day, I left my cellphone at work. It's bad because I use it to read books on the train. I always put it on a fixed spot. However, that day, I had to charge it but the charger was on my computer. Murphy's Law says: if anything can go wrong, it will. Exceptions are evil.

It's weird for an elevator to say "8th floor, going nowhere", but for a software developer, it's brilliant. If our software is free of exception processing code, it would be tremendously simpler. Uniformity is heaven.
 




更多我的博客文章>>>

所有跟帖: 

順便拜讀了您的其他文章,發現您思維深邃簡直就是金礦、寫作水平令人佩服,尤其是英文寫作能力 -heure- 給 heure 發送悄悄話 (6 bytes) () 11/09/2014 postreply 16:25:15

剛剛看到,才發現原來你是那個寫IT入門的人。看過1和2,很喜歡。在你的博客看到後麵的,不知道為什麽你的帖子會被刪除。 -bluespirit- 給 bluespirit 發送悄悄話 bluespirit 的博客首頁 (0 bytes) () 11/09/2014 postreply 19:27:27

請您先登陸,再發跟帖!

發現Adblock插件

如要繼續瀏覽
請支持本站 請務必在本站關閉/移除任何Adblock

關閉Adblock後 請點擊

請參考如何關閉Adblock/Adblock plus

安裝Adblock plus用戶請點擊瀏覽器圖標
選擇“Disable on www.wenxuecity.com”

安裝Adblock用戶請點擊圖標
選擇“don't run on pages on this domain”