×

Loading...
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。

how do you manage complexity (2)

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.

I'll end this post with my favorite song of today.

Sign in and Reply
Modify
Report

Replies, comments and Discussions:

  • 工作学习 / 事业与工作 / how do you manage complexity (2)
    • 劳驾,能翻译成中文吗?
      • 不好意思,打中文太慢。再说工作上的东西, 英文也有好处。
        • Neither do I.
      • 中心思想:复杂的一大根源是例外。没有例外,系统就会简单很多。妥善地处理例外,会导致事半而功倍。方法:A)化例外为例内;B)将复杂的东西分解成几个小东西,每个东西里面没有例外;C)将例外推到主系统以外。
        • 一个好的系统, 其Error management应该处理这些东东.
          • 我的 exception,不是 error。电梯不动,不是错误。如果它说 going nowhere,就是正常,x.substring(indexOf(x, " ")) 就可以取它的方向。但是如果它不动的时候一声不吭,就是一个例外,前面的代码就不工作,我就得先处理这个例外:if (一声不吭) 方向 = “nohwere”。
            • 估计搞IT的,都被你弄晕了。
              • 这巳经到了哲学的高度谈编程
            • 感情您这系统的exception/error是您程序自己定义的? 没写过规范吧? 另外Error management不是仅仅处理Error的.
              • 他说的更接近是谈good user experience。 有些情况不处理,虽不至于使系统当机,但没有提示会使用户不知所措。规根到底,还是bug。
                • 不是 user experience, 而是 programmer experience, and programmer productivity, and software quality.
              • 英语里的 exception, 其实就是我用的意思.
        • 简单问题复杂化,复杂问题简单化。项目就做好了。
      • 你跟贴太快,我当时正在想办法把代码整齐地显示出来。下面整出来了,希望能使我的观点更直观。
        // original code, from the web, probably in C#
        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));
        } 
        
        // With CommentStrategy and NullStrategy.
        private void ProcessLine(string line, IList result) {
            string typeCode = GetTypeCode(line);
            IReaderStrategy strategy = (IReaderStrategy)_strategies[typeCode];
            result.Add(strategy.Process(line));
        } 
        
        // Can be safely simplied to:
        private void ProcessLine(string line, IList result) {
           result.Add( _strategies[GetTypeCode(line)].Process(line) );
        } 
        
        
        • What's the point? The original code eliminates blank lines and comments, and rejects null type code as well. You just postpone the work. I think fail-first is much better and I don't like holding comments and nulls around.
          • The point is to turn blanks, comments and unknowns into normal cases, normal meaning to be handled the same way as other cases. As a result, client code is much simpler. The work isn't postponed. It's handled by CommentStrategy or NullStrategy.
          • It's debatable how we should handle an unknown line. I doubt the boss would be happy when he comes to work to find his reports missing because of a questionable line. But if you still want to throw an exception, you can do it in NullStrategy.
            • I thought you would reduce complexity rather than increase complexity. What did you achieve by creating 3 more classes and carrying those unused or error objects to downstream?
              In this example, I think the better way to manage complexity is
              1) fail-first, if you don't expect some inputs, reject them and throw exception right away, and do not pass them to downstream.
              2) make decision immediately whenever you can. I don't see how client code can be simpler by having to deal with CommentStrategy, BlankStrategy and NullStrategy. They don't have to see them at all.
            • You misunderstood the Null Object pattern. It should be used when null is a valid value. In your original code, null is invalid. In your case of your boss' report, it is valid. There is a big difference.
              • 你觉得许秀琴是真傻还是假傻?
                • 不知道耶。百度了一下才知道有这么个人。
    • I am just wondering who really understand what he was talking about? honestly I dont.
      • I don't neither. But perhaps somebody else do. I don't know much C++ now.
        • In your world it has "exception" too:)
        • You don't need to read the code to understand the article. I don't even know what language the code is written in.
      • 装嫩。
        • honestly I think you are puffing of nothig.
          • 对不起,开个玩笑。看《非诚勿扰》,女嘉宾评男嘉宾,觉得有趣,就扔上来了。
            • 仁者见仁,智者见者吗。很不错,高屋建瓴啊。受益匪浅。
              别骂我装老。哈哈
              • 真有点怀疑你是在装老. 你好像说你不是做计算机的, 你能认同, 俺有点惊讶.
                • (#6497825@0)
            • 有啥子Sorry的.
    • good post. 不老不嫩哈。
    • 看不懂那些CODE。 仰慕ING IT GUYS。
    • Bravo! The only thing I didn't like was the song.:-) The 中心思想 was a very helpful addition -- would recommend you make it a norm (rather than an exception) from now on.
      • 劳驾,能翻译成中文吗? -color_color(万宝全书...); 2.7 23:38 (#6497670@0)
        别骂人那
      • 那歌我听了上百遍·了,还是很喜欢。那句 “如是我闻”,俺可以反反复复地听一天。
        • 真不和谐。CCA夸你哪。
    • stock chart 的例子似乎说明的是 Single responsibility principle / loose coupling。另外整体感觉似乎你说的 complexity 是对如何使用 condition check 和 exception handling 来处理边界条件没有一个规范 (between a method and its caller) 引发的。
      exception 是用来对付 exceptional 的情况,throw exception + handle exception 在现代语言里也是“正经” (注意没有说正常) code path 的一部分。何时使用 ex,何时使用 condition checking,as ever it depends,似乎不该把所有的 ex 全部转化为 condition checking。
      • 我的 exception 不是 throw exception 的 exception,而是正常的“例外”。
        • 关于错误处理,是一直都有很大争议的课题,我就飘过先了。
          • 不是错误处理, 而是 usual design process.
        • 这句话我认真琢磨了一天,还是没明白。就酱紫吧。
          • programmer 的 exception,基本上就是 error。英文里的 exception,并没有这个意思。我要是用 variation,就没有这么多的误解,但我觉得 exception 更好。FileNotFound,是 error。电梯停下不走,不是 error。
            • 这就是你不对了。明知道Exception在编程里的意思和你表达的不同,还要举个程序做例子,这不诚心想弄晕大伙吗? 顺便说下,这电梯停下不走,为啥不是错误?电梯的功能里有停下不走这个feature的?
              • 电梯每到一层楼,可以往上,往下,或者不动,有傻错?我以前一个同学,毕业论文就是做的这个,他有一个算法,可以确定电梯什么时间停在哪一楼最优化。
                • 因为红卫兵在电梯里啊,它还不动,出了exception了。
                  • 彻头彻尾的书呆子呀
                • 一个电梯的算法,两个电梯的算法,三个电梯的算法。10楼的算法,20楼的算法,30楼的算法。7点到10点的算法,10点到15点的算法,15点到19点的算法,19点到7点的算法 ......
            • java: What Is an Exception? The term exception is shorthand for the phrase "exceptional event." c#: Exception handling features provide a way to deal with any unexpected or exceptional situations that arise while a program is running.
              • There is no big difference regarding exception in Java and C#.
                • Exactly, they are all same, that's my point. Exceptions are used to handle 'exceptional situations'. Period.
              • dictionary.com: an instance or case not conforming to the general rule. "going up", "going down" is the general rule. "going nowhere" comforms to it. "" doesn't. To not return "going nowhere" creates an "exception" for downstream code.
                • I think I get your point. You prefer to treat the exceptional cases as normal cases and thought that would reduce complexity. I strongly disagree. It adds burden to the code to handle normal cases and makes them
                  much more heavy and unmaintainable. That's the reason why modern languages support the concept of exception handling.
        • Where do you draw the line for "正常的例外"? The null type code in your example above looks an error/exception. 电梯停着不是例外是状态,但是它该走了还停着就是不正常的例外了。
          • 你当然可以把 null code 当”非正常的例外“,我们没必要争这个。即使把它当“非正常的例外“,你还是可以在NullStrategy里 raise exception,而不是在client code里。对client来说,所有的case都有一个strategy负责,no exceptions。这就是我的思想。
            • 你推迟到NullStrategy里raise exception的结果是时过境迁,没有原来的context,查错更困难。另外,你说的client的界限在哪里?如果,client只是接受list of strategies,那它根本没必要看到NullStrategy,也没有什么exception
              如果,client包括你引的code,也就是说client要implement这些strategy,那就更没有简化问题了。
              • 我说的 client 就是这个ProcessLine() method。几个新 strategy 作为adapter,把exception(not error!)转化成 normal case,大大地简化了这个method。
                • 那你写一个LineProcessor class,在你的client method里call lineProcessor.process(),是不是更简化了?明明代码和类都增多了,到底哪里简化了,只是转移了而已。
                  • 如果只是用一次,你有道理。我说的那个ComboBroker, 至少被用了十次。你这样真有点咬文嚼字的味道了。
                    • 唉!例子是你举的,用你的例子谈具体点,你又觉得是咬文嚼字了。
              • 在 NullStrategy 里raise exception,没有时过境迁,只不过多了一层函数调用。在那里处理的另外一个好处是,如果你以后改变政策了,你只用动一个很小的 class。
                • 在原来的method里的exception,可以清楚地指明null是在哪一个input的哪一行,当你pass NullStrategy到downstream以后,原来的context就没有了。
                  • 通常看了那一行text,应该知道错在什么地方了吧?如果还不行,你完全可以把行数pass给strategy。你还是在咬文嚼字。
              • 三个新class,是没有马上减少code。但是这三个class可能会被用很多次,此其一。以后维护这段code的人永远不用读这三个class的code,而code被读的时间要远远大于被写的时间,此其二。这样的处理,你不可能忘记测空行或注解行,减少bug,此其三。
                • 用原来的代码,这三个class根本不存在,维护的人更不会读这些code,不是更好?“这三个class可能会被用很多次”,别人怎么会不用读?人家本来三五行搞定的东西,加上个test,别人倒是真的不用读了。
                  • 假设这个code是某个data warehouse用来处理文件的,同样的code就可能出现在几十个class里面。你说是三个class一次好呢,还是50次的重复好?每次这些class有bug,维护的人都得读这些code。用我的方法,他们就不用读。你问为什么?你读过几次 Sun 的 Java source code?
                    • 为什么“同样的code就可能出现在几十个class里面”?人家原来一个method不就解决了吗?要reuse,把这个method wrap成一个LineProcessor的class也行。你这里是为了当前不存在的而以后可能有的问题做了over-design。
              • 许秀琴是真傻假傻,我们可以辩到天亮,到头可能还是没个结果。
                • 有没有结果不重要,和有意思的人辩论有意思的事倒是件有趣的事。
                  不过,大家都太和气了,反倒没意思了。
    • It seems you have a thorough understanding on design patterns. Good article!
    • I have to disagree with the "making exceptions normal". Exceptions by its name, are exceptions, they are not normal, and need to be dealt with. Elevator going nowhere? it is not normal, you need to call repairman!
      本文发表在 rolia.net 枫下论坛OP posted an example of masking exceptions. Suppose you were asked to write a function to read a file and fill a given buffer with file content. Sure, you expected errors of file not found or access denied, are you expected to propagate the error information to your caller? Maybe the caller needs to know that you failed to open the file and notify user or write a log? If the caller expected error information from you, have you documented how the error will be passed out (throw exception or return error code)? Even if you opened the file successfully, have you prepared for the file is being too large and buffer is not big enough? Have the caller been prepared for the file has been corrupted and the content read is not in the format expected?

      Elevator not moving, it is not normal, should you make a call to administrator, call for repairman, or just standing there silently?

      OP also posted using design patterns and writing mock-ups. Those are concepts and not generic rules. You have to rely on engineers' experience and talent in dealing with complexities. There were few systems that are more complex than Windows, I just pick few examples from it.

      If you are familiar with COM, you have known IDispatch interface. Its concept is simple: you can expose arbitrary number of functions through IDispatch interface, each function is given a unique number, and the when those functions are being called, all parameters are packed into an array with each element of type VARIANT which can contain any data type, and it could even be another IDispatch object.

      The goal? If somebody gives you an IDispatch object, you can know all the functions it provides and all the parameters information. The writer of the IDispatch object can add new functions into it without affecting existing code.

      How flexible is it? You may also have heard of web services. Microsoft provided a utility Soap Toolkit, which allows you pass a wsdl to it, it will build the function table in memory dynamically and you can call the web service functions through the IDispatch interface, from script languages.

      I believe few people here likes UAC in Vista. However there was great engineering under it. In the days of XP, programs are running under admin privilege and they can write to HKLM or Windows directory. With UAC turned on in Vista, only programs running with elevated privilege can do so. For legacy programs that are running under protected privilege and still trying to write to those forbidden locations, instead of failing the write operation, Microsoft introduced “virtual store” which redirects the write operation to a location to allow those programs continue running properly.

      Kaspersky introduced “safe run” feature in recent two years and it is based on same concept. Once a program was added into safe run list, all its write operations that are considered could have impact to system stability will be redirected to a temporary location without program’s awareness. Web browsers are typical candidates for safe run.

      If you are a Windows programmer, I strongly recommend reading “Windows Internals Fifth Edition”. It is a great book. Not only does it tell details how Windows works, you can also learn many great designs inside Windows. Take an example of file I/O stack: when you read something from a file, I/O manager will generate an IRP and it will pass at least three different driver stacks before it can get to hard disk controller: file system driver <-> volume driver <-> disk driver. Is it necessary? Why can’t I/O manager talk to device directly? The layered driver stack design has its purpose: anti-virus software can use file system filter driver to scan for viruses; Windows uses file driver for per-file-basis encryption; ISV can use volume driver to implement RAID functionality; ISV can also use disk driver to implement virtual disks (think RAM disk, virtual CD/disk). Each layer has its own purposes and ISVs can insert their driver into the stack to implement new functionalities. I call this is how complexity is managed.更多精彩文章及讨论,请光临枫下论坛 rolia.net
      • When elevator arrives at a floor, it can go up, go down, or stay put. Staying put is a decision, not a mal-function. If you write a function to return a string, do you use "" or "stay put" or "go nowhere"? We make many such decisions every day.
      • 上班不敢细看,以为你转贴。你说的 layering 很好,我以后会写。先写 exception (not error!),是因为我觉得它更重要,更 pervasive。
      • Great design in Windows? Definitely an exception。Programs writing to HKLM or Windows directory? The best example of Windows stupidity.
        • What have been done are already done. Running programs with admin privilege is a stupid design, Microsoft leaned it in a hard way, and they paid great effort for fixing it (they have to use kernel filter drivers for file and registry redirection).
    • Good topic. 处理exception是最头大的问题. It can easily get out of control.
    • 很有同感,但你说咱怎么就总结不出来呢.差距啊.
    • 乍一看以为讨论人际关系,原来是编程。其实最复杂的还是人。
    • It's amazing how a high-level discussion turned to micro-detailed plumbing level debates.:-) Exception is a relative concept - relative to one's ability to anticipate. It's something out of your "rader" (expectation) FOR NOW.
      As the scope of your radar expends, the universe of exceptions shrinks.

      If the god (or the Buddha:-) is a programmer, he would see no exception!
      • 还是如来一针见血啊. 昨晚我就觉得讨论没意思, 只是没有你这么看的高.
        • 你要不举那几个程序的例子,估计大伙就没那么高兴致了。做编程的,看见code就眼红往上冲。
        • 看完了所有的回帖,是这样,这个帖子没有太大的意义。
          你所设想的三种解决方法基本上都很难实现。

          设计模式解决的是扩展性和化繁琐为简单的问题。但是真正的例外并非那么简单。现实中最大的例外来自于你没有考虑到的例外,如果没有考虑到,你如何去handle?

          在我的职业生涯中,我感到更多的是“和例外一起生活”。当有了例外以后,我们把它找出来,然后针对它写出处理程序。然后再对付下一个例外。因为例外是从你想不到的地方出现的,你自然不可能提前针对它来进行设计。如果你对一个可能出现的例外提前设计了,它也许是好的,但更多的会是over design。实际上你发现这个地方可能会有例外的话,一个简单的判断可能更好。你说的几个模式,我认为更大的用法是扩展,而不是处理例外。

          但是我最近倒是考虑一些真的有用的工具,用工具来检测例外。比如检测内存的泄露,检测未初始化,检查对输入参数的有效性判断,但是去除重复的有效性判断。这些工具会比较有意思。它在一个常用的级别上剔除了例外。
      • 仁者见仁,智者见者吗。很不错,高屋建瓴啊。受益匪浅。 -thornthorn(Holy Moly); 2.8 07:17 (16 bytes. #6497826@0)
      • The center of the debate is whether expanding the scope of your radar is a good thing. My answer is not in most cases. It is much better and easier to define the scope clearly as early as possible than
        leave it undefined and try to expand it in the middle of a project or process. It adds system complexity, communication cost and maintenance cost. And, I can hardly see benefits even in micro level.
        • Did I hear "It's better to refuse to grow up" -- or "It's better to deny that we have actually grown up"? :-)
          Sorry if the analogy sounds a bit offending -- but I hope it conveys what I was trying to mean.
          • The metaphor has nothing offending, in fact, it shows, without a clear definition (here, of "growing up"), how easily a serious discussion can turn into a game of wording.
            • The point was -- typically the scope of your radar is constantly growing. At any given time, it's better not to defer anyting you can anticipate into an "exception".
              Real "exceptions" exist to give you a chance to learn - and hence to expand your scope of radar - which in turn converts some "exceptions" into "non-exceptions". In dealing with "real exceptions" -- i.e. something you really cannot anticipate *at this time* -- you would typically leave some informative trace, and make sure things exit or move on (with some default state) gracefully.

              Again, this is a learning process -- eventually you may (if ever) reach an equilibrium where all remaining "exceptions" are truly unanticipatible -- due to random factors or "god's will":-). This process typically lasts well beyond production, and should be considered an important component of maintenance.

              When I said "exception" -- it refers to the English term, not the programming syntatic term.
              • Very insightful. Still, I would make one point clear: treating exceptional cases as exceptions does not mean you don't or are not able to handle exceptions. In other words, the scope of radar does not change at all.
                You just handle the exceptions one way or the other. Here, it is more about when to deal with exceptions and how to deal with exceptions. Usually, it is more a preference in modelling rather than a learning process, unless your point of view is only from the "normal process" instead of the whole system.
                • I guess the difference is on terminology -- what I meant by "exception" is probably "uncategorized/uncharted exception" in your case.
                  • You are absolutely right. However, I don't think the "exception" in wincity's post refers to the "uncategorized/uncharted exception".
    • 太太早上和我说有人在讨论manage complexity,她看不懂。偶就来看看。没想到有见大侠们。
      首先,我还在找trading system的工作,有机会的话招呼一声。

      I agree with that "Exceptions are evil". Just a few more detailed issues. Firstly, please don't use "new" after throw. It's a very easy way to create memory leak. Secondly, exception is slow. In some cell phone platform, try/catch are forbidden because they spends too many resources. I don't think it should be used in a trading system at all.

      And once time somebody asked me a very strange question. "How to prevent a method throw an exception?"

      The answer is "Put throw() after your method's declaration."

      But the question is why they asked such a question?

      Finally, I found the answer. It's because some compile will save an exception valuable creating time when it founds throw().
      • 我的 exception 不是你说的 exception.
        • 哦,只是刚才看了你的code以后……
          没有注意到你写的是c#
          没有exception自然是理想状态,现实生活中可能么?

          _strategies[GetTypeCode(line)].Process(line)

          How about when _strategies[GetTypeCode(line)] returns null?
          • 做编程的,看见code就眼红往上冲。 -coolmao(酷猫*Zensunni); 09:23
            • 呵呵,这个是写code的人的本分。写code的人,读源码更重要。
              我昨天又发现了一个同事,他在一个类里面定义了一个标志位,而之前另一个人定义了一个想同功能的标志位,于是两个标志位控制了同一个功能,日积月累,两套控制都有人用。结果一团糟。

              所以从现实当中,我感觉,所有的想法都真的只是理论上的。再好的设计,碰到一个不负责的人来改也是白搭。做程序员最重要的就是读代码。只有彻底地理解了前人的设计以后,才动手改进。
    • 这么理论化的帖子怎么变成code大讨论了.如果抛开code,从idea,concept,design或者architecture的角度就比较容易理解搂住的意图了.当然我也只是理解了一部分我经历过的有感触的部分.
      • 楼主为什么要用code做例子,因为code具体形象地说明idea。跟着的讨论也是一样。你把讨论的code的每一行当成component,module和system去读,你会更容易理解我的观点。
        • 你俩只是角度不同.在不同的需求下都对.我觉得搂住表达出了一种思维设计方式,只是给我们一个参考.但大家都是老中医了,都知道要看人下方子的.如果谁敢说我的方法最好万能,我也砸他.
      • 讨论code不丢人,Anders Hejlsberg 讲keynotes时还写code呢。Arch-design做一段时间以后就发现最基本的一些原理比如Single responsibility principle / Open/closed principle,甚至更基本的exception handling才是最重要又最容易被忽视的。基本功不扎实高屋建瓴挺要命的。
        • 你和其他一些人说的都有道理.但我自己只是愿意从别人的角度顺着别人的思路去理解别人的观点,多学习一下别人的思路对我没损失.我只是打酱油的.大家继续.
        • 确实如此。具体的code和architecture的设计是基于同样的原理。完全抛开具体应用来夸夸其谈系统设计的话,是没有多少意义的。