Total Pageviews

2017/06/10

[Design Pattern] Builder Pattern

Definition of Builder Pattern

  • The builder pattern, as name implies, is an alternative way to construct complex objects. 
  • A builder pattern is more like fluent interface. A fluent interface is normally implemented by using method cascading (or method chaining).
  • Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.”

A complete Java builder pattern example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package albert.practice.designpattern.builder;

import java.util.regex.Pattern;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class User {

    private final String firstName;
    private final String lastName;
    private final Integer age;
    private final String phone;
    private final String email;

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.email = builder.email;
    }

    public static class UserBuilder {
        private String firstName;
        private String lastName;
        private Integer age;
        private String phone;
        private String email;

        public UserBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public UserBuilder age(Integer age) {
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }

        public User build() {
            User user = new User(this);

            // Do some basic validations to check
            if (!isEmailValid(user.getEmail())) {
                throw new RuntimeException(user.getEmail() + " is invalid Email format!");
            }

            return user;
        }

        public Boolean isEmailValid(String email) {
            Boolean isValid = Boolean.FALSE;
            Pattern EMAIL_PATTERN = Pattern.compile("^\\w+\\.*\\w+@(\\w+\\.){1,5}[a-zA-Z]{2,3}$");
            if (EMAIL_PATTERN.matcher(email).matches()) {
                isValid = Boolean.TRUE;
            }
            return isValid;
        }

    }
}


Example to use above builder pattern to create a User object
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package albert.practice.designpattern.builder;

import albert.practice.designpattern.builder.User.UserBuilder;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BuilderTest {
    public static void main(String[] args) {
        User albert = new UserBuilder()
                .lastName("Kuo")
                .firstName("Albert")
                .phone("1234567890")
                .age(30)
                .email("test@gmail.com")
                .build();
        log.debug(" user1 = " + albert.toString());

        User mandy = new UserBuilder()
                .lastName("Yeh")
                .firstName("Mandy")
                .email("yeh@gmail.com")
                .build();
        log.debug(" user2 = " + mandy.toString());
    }
}



Benefits and Advantages

  • The number of lines of code increase at least to double in builder pattern, but the effort pays off in terms of design flexibility and much more readable code. The parameters to the constructor are reduced and are provided in highly readable method calls.
  • The constructor is private, which means that this class can not be directly instantiated from the client code.
  • The class is once again immutable. All attributes are final and they’re set on the constructor. Additionally, only provide getters for them.
  • The builder uses the Fluent Interface idiom to make the client code more readable.


Conclusion
Using builder pattern for constructing objects when having a lot of parameters, especially if many of these parameters are null and when many of them share the same data type. A developer might feel that the extra code to implement a Builder might not justify its benefits for a small number of parameters, especially if the few parameters are required and of different types. In such cases, it might be considered desirable to use traditional constructors or, if immutability is not desired, use a no-argument constructor and require the client to know to call the necessary "set" methods.


Reference
[1] http://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html?page=2
[2] http://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/

2017/06/09

[Eclipse] project configuration is not up to date with pom.xml

Problem
I have Maven Project in Eclipse Mars.

One day I have an error in my project, but it does not have any negative effect to my implementation or maven build :


How-To
Although the root cause is still unclear, it works to follow these steps to get rid of this annoying error:

Step 1. Click this error => right click => Quick Fix


Step 2. Click Finish in Quick Fix window

Fixing problem in progress:

After fixing process, the problem is disappeared:

2017/06/08

[Eclipse] EclEmma - Java Code Coverage for Eclipse

In computer science, code coverage is a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs. A program with high code coverage, measured as a percentage, has had more of its source code executed during testing which suggests it has a lower chance of containing undetected software bugs compared to a program with low code coverage.

EclEmma is a free Java code coverage tool for Eclipse, it brings code coverage analysis directly into the Eclipse workbench.


Prerequisite
Prepare your unit test programs:



Execution
After you installed EclEmma Plugin, you can run  Coverage as => JUnit Test


Then you can get the converge analysis report


Summary
While 100% code coverage is nice, it's not a good metric to blindly follow. 100% code coverage doesn't tell you anything other than you have tests that execute all your lines of code. Your code can still have bugs if that covered code does the wrong thing or doesn't do enough. 


Reference
[1] https://en.wikipedia.org/wiki/Code_coverage
[2] http://www.eclemma.org/
[3] https://stackoverflow.com/questions/26360245/try-with-resource-unit-test-coverage


2017/06/07

[webMethods] Global Variable

Problem
若我們有些變數是全域使用的,在 webMethods 中要設定在哪邊,才能讓所有的 Java Service、Flow Service 使用?

How-To
可以在 Integration Server 設定 global variable,步驟如下:
Step 1. 進入 Integration Server Administrator,在 Navigation panel 中選擇 Settings => Global Variables


步驟 2.  按下  Add Global Variable


步驟 3. 輸入 key (Global variable 的名字) 與 value (Global variable 的值),並按下 Save Changes



接下來,我們可以建立一個 Flow Service 來做測試
步驟1. drag and drop debugLog 此套件到 Flow Service 中,點選 Pipeline tab,並點選 message


步驟 2. 在 message 中輸入 global variable 的名字,頭尾用 % 包起來,記得要勾選 Perform global variable substitution 此選項,並按下 OK 按鈕

步驟 3. 執行此 Flow Service 進行測試



2017/06/06

[Eclipse Plugin] EasyShell

While working in eclipse you may want to open selected file from project explorer to Windows File Explorer. 
One way is by selecting file, go to properties, copying path and open Windows File Explorer then paste that path. 



Another convenient way is to utilize EasyShell plugin

This Eclipse plugin allows to open a shell window or file manager from the popup menu in the navigation tree or editor view. Additionally it is possible to run selected file in the shell, copy file or directory path or run user defined external tools. 

EasyShell usage looks like:



Reference
[1] https://marketplace.eclipse.org/content/easyshell

2017/06/05

How to use Apache Commons CSV to Read/Write CSV file

Step 1. You need to add this dependency to your pom.xml
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.4</version>
</dependency>


Step 2. Create a POJO class
package albert.practice.csv;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class OpcVo implements Serializable {

    private Integer ns;
    private String identifier;
    
}


Step 3. Here has an example regarding how to read/write CSV file via Apache Commons CSV
package albert.practice.csv;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CSVTest {

    // Delimiter used in CSV file
    private static final String NEW_LINE_SEPARATOR = "\n";

    // CSV file header
    private static final String[] FILE_HEADER = {"ns", "identifier"};

    // OpcVo attributes
    private static final String NS = "ns";
    private static final String ID = "identifier";

    public static void main(String[] args) throws IOException {
        String csvDirectory = "D:/work/AOCS/csv/";
        String csvFileName = "test.csv";

        CSVTest test = new CSVTest();
        // test.writeToCSV(csvFolder.concat(csvFile));
        List<OpcVo> opcs = test.readFromCsv(csvDirectory.concat(csvFileName));
        opcs.forEach(opc -> log.debug(opc.toString()));
    }

    public void writeToCSV(String fileName) throws IOException {
        List<OpcVo> opcs = getDummyData();

        // Create the CSVFormat object with "\n" as a record delimiter
        CSVFormat csvFileFormat = CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR);

        try (FileWriter fileWriter = new FileWriter(fileName);
                CSVPrinter csvFilePrinter = new CSVPrinter(fileWriter, csvFileFormat);) {
            // Create CSV file header
            csvFilePrinter.printRecord(FILE_HEADER);

            // Write a new OpcVo object list to the CSV file
            for (OpcVo opc : opcs) {
                List dataRecord = new ArrayList<>();
                dataRecord.add(String.valueOf(opc.getNs()));
                dataRecord.add(opc.getIdentifier());
                csvFilePrinter.printRecord(dataRecord);
            }
        } catch (IOException e) {
            throw e;
        }
    }

    public List<OpcVo> readFromCsv(String fileName) throws IOException {
        // Create a new list of OpcVo to be filled by CSV file data
        List<OpcVo> result = new ArrayList<>();

        // Create the CSVFormat object with the header mapping
        CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER);

        try (FileReader fileReader = new FileReader(fileName);
                CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat);) {
            List dataRecord = new ArrayList<>();
            // Get a list of CSV file records
            List<CSVRecord> csvRecords = csvFileParser.getRecords();
            
            for (int i = 1; i < csvRecords.size(); i++) {
              //Create a new OpcVo object and fill this data
                CSVRecord record = csvRecords.get(i);
                String ns = record.get(NS);
                String identifier = record.get(ID);
                result.add(new OpcVo(Integer.valueOf(ns), identifier));
            }
        } catch (IOException e) {
            throw e;
        }

        return result;
    }

    private List<OpcVo> getDummyData() {
        OpcVo opc1 = new OpcVo(2, "Channel1.Device1.FireZone_01");
        OpcVo opc2 = new OpcVo(2, "Channel1.Device1.EmergencyPushButton_01");
        OpcVo opc3 = new OpcVo(2, "Channel1.Device1.EmergencyExitWindow_01");
        OpcVo opc4 = new OpcVo(2, "Channel1.Device1.EmergencyExit_01");

        return Arrays.asList(opc1, opc2, opc3, opc4);
    }
}




2017/06/04

[Windows 7] 如何將資料上傳到遠端桌面?

Problem
若我用 Windows 的遠端桌面連線程式連上遠端的電腦,我該如何將本機的檔案上傳到遠端的電腦?

How-to
步驟 1. 打開遠端桌面連線,點選『本機資源』,點選『其他』


步驟 2. 勾選要分享的目錄,如畫面中的隨身碟


步驟 3. 連線到遠端的電腦以後,可以在檔案總管看到 步驟 2. 勾選的磁碟機,若有檔案要從遠端複製回本機端,或者是從本機端複製到遠端,可以利用此磁碟機當作是分享的橋樑


2017/06/03

[webMethods] 如何從 Java Service 中讀取 Property File

在 Java Service 中,有些設定值我希望不要 hard code 在程式中,要搬到 property file 供日後的設定之用,該如何從 Java Service 中讀取 Property File

property file 檔名為 opc_config.properties ,
內容如下:
opc.url=opc.tcp://192.168.1.1:49320
opc.retry.interval=5
opc.max.retries=5
opc.sleep.ms=5000

我目前的開發的目錄是在 Acme 的 package之下:


property file 就要放在 [IntegrationServer 安裝目錄]\instances\default\packages\Acme\resources 之下

值得注意的是,當我們在 load 此 property file 時,路徑規範是 packages\\[你的 package name]\\resources\\[你的 property file name],如 packages\\Acme\\resources\\opc_config.properties ,若沒按照此規範會出現 FileNotFoundException

Sample code 如下:

    /** 
     * The primary method for the Java service
     *
     * @param pipeline
     *            The IData pipeline
     * @throws ServiceException
     */
    public static final void PropertyFileUtils(IData pipeline) throws ServiceException {
        String config_file = "packages\\Acme\\resources\\opc_config.properties";
        
        try {
            Properties properties = loadProperties(config_file);
            
            String opcUrl = properties.getProperty("opc.url");
            String retryInterval = properties.getProperty("opc.retry.interval");
            String maxRetry = properties.getProperty("opc.max.retries");
            String sleepMs = properties.getProperty("opc.sleep.ms");
            
            logger("opcUrl = " + opcUrl);
            logger("retryInterval = " + retryInterval);
            logger("maxRetry = " + maxRetry);
            logger("sleepMs = " + sleepMs);
            
        } catch (IOException e) {
            throw new ServiceException(e);
        }
    }
    
    // --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---
    
    public static Properties loadProperties(String config_file) throws ServiceException, IOException{
        Properties properties = new Properties();
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(config_file);
            properties.load(inputStream);
        } catch (IOException e) {
            throw new ServiceException(e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return properties;
    } 
    
    public static void logger(String message) throws ServiceException {
        IData input = IDataFactory.create();
        
        IDataCursor inputCursor = input.getCursor();
        IDataUtil.put(inputCursor, "message", message);
        IDataUtil.put(inputCursor, "function", "customLogger");
        IDataUtil.put(inputCursor, "level", "INFO");
        inputCursor.destroy();
    
        try {
            Service.doInvoke("pub.flow", "debugLog", input);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }
    
    // --- <<IS-END-SHARED-SOURCE-AREA>> ---

相同的,如果你有一些設定用的檔案如 csv 等,也可以放在 resources 目錄下,透過相同的方式皆可讀取得到

Reference
[1] https://goo.gl/EFbLkg

2017/06/02

[閱讀筆記] 惡魔財經辭典 (The Devil’s Financial Dictionary) [2/6]


  1. 會計事務所負責稽核客戶的財務及發行之投資商品,因此也能協助在財務、股票或債券價值上作假,也便於內線交易
  2. Blue chip (藍籌股)指的是績優股,是最大型、最多人持有的股票。blue chip 一詞出自賭場,藍色的籌碼是賭場裡最高價的籌碼
  3. 在華爾街,成功常常不只取決於能力,運氣也相同重要
  4. Book value (帳面價值)常被譏笑是衡量公司價值的爛方法,因為無法完全囊括專利、軟體、行銷創新等無形資產的潛在價值,也無法精準估計公司創造收益的潛力。只能看出所有用的之產減掉負債後所剩下的價值,話雖如此,book value仍是一個粗略的指南,可讓持股人知道若情況不對,公司還剩下多少價值
  5. 股市跌了一波以後似乎穩定下來,技術分析師就說這是在打底(form a bottom),只要開始上漲就說底部完成(complete a bottom)。若接下來不漲反跌,技術分析師又說市場在打另外一個底(bottom),底部一個一個打,打個沒完,一路往「零元」打去
  6. Broker 這是個形容某人取用(很可能榨乾)他人財富的字根,投資人應該謹記在心中
  7. 幾乎打從金融市場誕生以來,人們就明白 bubble 會在一瞬間從「興奮」、「痛快」轉為「災難」。在更近代,只要是投資人認為價格過高的資產,就一律用 bubble 來形容。然而,能準確辨識出 bubble 並且成功避開從來就不容易,很多都只是放馬後砲而已
  8. 股價上漲期間,會導致投資人認為自己的智商也走高。等到價格必然下跌後,他們才知道,這兩者的走高都只是暫時的
  9. Bond call 是指贖回債券,公司或政府提前將發行的債券贖回(pay off),通常是最不利於投資人的時間點
  10. 資本(capital)就像牲畜一樣,如果沒有好好看管的話,容易走丟、跑掉,甚至死亡
  11. Bear market 往往不在重摔巨響中結束,而是在低鳴聲中劃下句點,逐步步入麻木黑暗中。Bull market 也不是在恐慌的投資人拋售後就開始,而是絕望的投資人麻木到連賣都不賣時
  12. 投資管理人犯的錯有兩種:一是「跟著眾人一起錯」(這時候不會有人責怪他,因為大家都犯同樣的錯),二是「只有他一個人錯」(這時候他就會向個白痴一樣)
  13. 唯一可以大敗大盤的方法是「不從眾而行」
  14. 基金經理人常會交易過度頻繁、過度著眼於模仿大盤動向,卻忘了身為一個基金經理人真正該做的事情是「選出最低價的潛力股,然後長期持有」
  15. Central bank (中央銀行)跟 weathervane(風向雞)沒什麼不同,兩者都會隨風轉向,只不過,中央銀行那些人以為風往哪邊吹是他們決定的。殊不知,他們的預測從不可靠、對於通膨根本無法預防、讓失業率更加惡化
  16. 金融市場最根本的屬性就是 uncertainty,每當你自以為知道某事一定會發生,金融市場就會證明你錯了。每當混亂或動盪清晰可見,專家們就會宣稱「投資人痛恨不確定性」,可是,「不確定」是投資人面對的「確定」狀態
  17. 痛恨「不確定」是浪費時間與精力,不如乾脆去痛恨地心引力或抗議時間流逝算了。唯一的 certainty 就是 uncertainty 永遠不會消失。你要習慣他,不然就完全離開金融市場
  18. 一份好的 checklist 可以提供一種架構,迫使投資人去做仔細、獨創的研究,多多向外蒐集資料來挑戰自己的看法,以免受制於「驗證偏誤」(confirmation biasis)。飛機駕駛和醫護人員都會採用 checklist ,這麼做可以拯救人命。同樣的,一份好的投資 checklist 也可避免做出衝動決策
  19. Cigar butt (雪茄屁股)是指股價非常低廉的股票,因為低廉,所以就算該公司經營不善,股價仍會上漲。誠如巴菲特所言:「如果買一支股價夠低的股票,通常有機會以不錯的獲利出脫了結,儘管該公司長期的表現可能很糟糕。」但是,在現今的金融市場,想要找到 cigar butt 很難
  20. 當分析師使用 clearly (顯然地)這個字眼時,只有兩種狀況:
    1. 假裝他們知道接下來會發生什麼事情,但是沒有令人信服的證據
    2. 描述已經發生的事情,宣稱他們早就知道
  21. Commodities (大宗物資、原物料) 的賺賠操作有三種模式
    1. 透過市場價格的漲跌(也就是spot,現貨價)
    2. 滾動利益(roll return,轉倉收益),也就是如果你賣掉這個月期貨的價格,高於下個月期貨的買入成本
    3. 賺取抵押品(也就是你拿來擔保借款的東西)的利息
  22. 從歷史來看,Commodities (大宗物資、原物料)的長期績效要靠「滾動利益(roll return,轉倉收益)」,但由於後來大量新進投機客的熱錢湧入,扭曲了期貨市場價格,roll return 的效益逐年遞減。2008 年金融危機後,各國央行往零利率的方向走,抵押品的報酬也跟著縮水。因此大宗物資的高報酬已經不在,但還是有很多天真的投資人爭相投入
  23. 不同於債券、股票、房地產,大宗物資的現金流無法預測。所以,一旦完全要仰賴別人願意付多少錢,就比債券、股票、房地產的風險更高,只能任憑市場宰割
  24. 信心滿滿是有害的,投資人現在越有信心,日後難過的機率就越高。不過,幾乎沒有人能在當時認知到這點
  25. 每個人都會有 confirmation bias (驗證偏誤),因此投資人必須強迫自己透過 checklist 之類的程序,尋求及思考其他反面證據。詩人 Ogden Nash 曾說過:「已經有定見的腦袋就像一道只能像外打開的門,用再多的事實來推他,結果只是關得更緊而已」
  26. 恐懼的情緒會傳染,從一個投資人擴散到另外一個投資人,從一個市場擴散到另外一個市場,甚至擴散到全世界。目前已知療法只有三種:時間、隔離、耳塞
  27. 很多專業投資人都說自己是逆向操作的人(contrarian),但是幾乎沒有一個是
  28. 市場溫和下跌是指下跌幅度不超過 10% ,不過並沒有一個正式的定義。市場行為必須適當地 correct (修正),價格一路上揚本來就不對
  29. 分散投資要達到最大效果,投資組合中的標的就不可高度相關。可是,如此一來就必須持有一些績效較差的標的,而不能一味追逐當前最熱門的標的
  30. Counterparty 是指交易對手,如果你是賣方,買方就是你的 counterparty;如果你是賣方,買方就是你的 counterparty。但是,不管你是在哪一方,只要有人下單,就是券商歡呼的時刻,無論買或是賣,券商都可以收取手續費

2017/06/01

[閱讀筆記] The Black Swan: The Impact of the Highly Improbable (1/3)


  1. 黑天鵝的三大特性
    1. rarity (罕見):過去的經驗讓人不相信其出現的可能
    2. extreme impact (造成重大衝擊):只要一發生,就會造成重大的衝擊
    3. retrospective predictability (事後諸葛);一旦發生,人會因為天性使然而作出某種解釋,讓這事件成為可解釋或可預測
  2. 人們太少反思自己所相信、習以為常的事情
  3. 人類是相當膚淺的動物,我們都知道預防重於治療,但是我們通常不會去讚賞做風險預防動作的人,反而會去讚賞壞事情發生後去收尾的人
  4. 我們的世界是被極端、未知、無法預測的事物所主宰,然而人們卻聚焦在已知、重複發生的事物上
  5. 我知道誰的言論是錯誤,但是不代表另外一個言論是正確的。如果我看到一隻黑天鵝,我可以確定不是所有的天鵝都是白的。如果我看到有人殺了人,我可以幾乎確定他就是罪犯;但是如果我沒有看到他殺人,我無法確定他是無辜的。
  6. 我們總是假定歷史是是根據某種邏輯產生的,但是其實我們只有看到一連串的事件,不是邏輯,只是在猜測這一連串的事件是怎麼產生的
  7. 黑天鵝會出現是,人們聚焦於少量的不確定的來源,但是災難卻是從非聚焦的地方所產生
  8. 真實的世界是非線性的,而且會比你想得更非線性。線性的關係在真實世界是非常罕見的,你只會在教室或是教科書裡面才會看到,因為那是要讓你更容易理解
  9. 感恩節之前的火雞會因為被人類飼養對人類的信任度慢慢提高,如果你是火雞會認為自己沒有任何危險,直到感恩節那天,火雞的"黑天鵝"發生(超出它想像的事件),莫名其妙的被做成感恩節大餐
  10. 在真實世界裡,人們總是會較重視 What I did for you,較漠視 what I avoid for you。人們會看到911事件後對罹難者家屬的照顧,卻不會看到立法強制開車要繫安全帶,保護你人生安全的立法者
  11. 當你看到某個事件發生的原因是"因為"什麼樣的關係所導致,對於這個原因,請先保持懷疑的態度,小心求證
  12. 人是一個很膚淺的動物,只會注意到所看到的事物
  13. 為什麼我們會看不見黑天鵝,因為我們只擔心過去已經發生的事情,忽略了之前沒發生過的事情。這是因為人們對於沒發生過的、沒看過的事物,太過抽象,以致於忽略它、無法從中學習到教訓。
  14. 人類的知識會逐漸增加,但是威脅人們的是快速增加的自信。人類的傲慢源自於其有限的知識,人們總是高估自己所知道的,而低估不確定性
  15. 人類實際知道的知識,與自己認為自己知道的知識,常常有顯著落差
  16. 很多專家的預測並不準確,因為他們是根據不會重複發生的過去,來預測未來。我們頂多可以透過網站,預測明天戲院幾點開門
  17. 專家最大的問題是,他們不知道他們哪裡不知道
  18. 預測要正確,事情的發生要有規律性,如果沒有規律性,預測勢必失敗
  19. 人們常把成功歸因於自己的能力,把自己的失敗歸咎於外在的、無法控制的隨機事件。我們只對好的事物負責,對壞的事物卸責
  20. 因為我們不夠了解未來,所以我們無法做好妥善規劃。所以,在規畫的時候要牢記,我們規劃的限制是什麼