[活動筆記]單元測試這樣玩就對了

應該知道的事:

案例一、數值區間

1
2
3
4
5
6
假定給任一整數區間
ex:
(1,6] = {2,3,4,5,6}
[-2,4) = {-2,-1,0,1,2,3}
透過一個function(x)檢查x是否包含在整數區間內,
並撰寫測試,驗証 function(x)是對的。

解析

如上範例所示,
「(」「)」小括號(parentheses)表示OPEN(不包含,大於或小於)
「[」「]」中括號(square brackets)表示CLOSE(包含,大於等於或小於等於)
(1,6] , 代表這個區間大於1小於等於6,包含的整數有 2、3、4、5、6
[-2,4), 代表這個區間大於等於-2小於4,包含的整數有-2、-1、0、1、2、3

這題比較單純,只需要考慮所有的情況,
並且寫成單元測試即可。

  1. x 落在區間內
  2. x 落在左邊界外
  3. x 落在右邊界外
  4. x 落在左邊界上,左邊界為OPEN
  5. x 落在左邊界上,左邊界為CLOSE
  6. x 落在右邊界上,右邊界為OPEN
  7. x 落在右邊界上,右邊界為CLOSE

有幾種特殊的情境,特別說明一下

  1. 假設區間為(0,1),這個區間是不包含任何整數
  2. 假設區間為(1,1),這個區間是不包含任何整數,且不包含任何數值
  3. 假設區間為[1,1],這個區間恰巧包含1個整數,且只包含1這個整數
  4. 假設”區間”為[2,1],或任何左邊界大右邊界的表示,這不是一個正確的區間,將要作例外處理。

讓我們回歸單元測試,
這裡的重點是一個測試只作一件事,
只把一個情境釐清,並且在測試的程式碼中
明確的表達測試目的

1
2
3
4
5
6
7
8
9
10
11
12
private int leftBound = 1;
private int rightBound = 6;
private int testNum = 4;

[TestMethod]
public void IncludeWhenLeftOpenRightClose()
{
var checker = new RangeChecker(Bound.Open,this.leftBound,Bound.Close,this.rightBound);
bool expect = false;
bool result = checker.IsContains(testNum);
Assert.IsTrue(result);
}

案例二、現在時間轉字串

1
2
3
寫一個方法GetNowString,不傳入任何參數,
取得現在的時間字串,需要精準到豪秒。
再寫一個測試去測試這個方法是對的‧

版本1

最簡單的寫法:

1
2
3
4
5
6
7
public class DateHelper
{
public string GetNowString()
{
return DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss ff");
}
}

撰寫測試

1
2
3
4
5
6
7
8
9
[TestMethod]
public void GetNowString()
{
var
//// 寫不下去,因為我們無法凍結系統的時間
string expect = "2017-04-19 20:45:17.88";
string result = dater.GetNowString();
Assert.AreEqual(expect, result);
}

解析

GetNowString與系統的時間DateTime.Now,
是具有耦合性,要解耦需要透過一些IoC的手段去處理。

版本2

利用繼承的方法,作出假的類別

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
public class DateHelper
{
protected DateTime now;
protected virtual DateTime GetNow()
{
now = DateTime.Now;
return now;
}

public string GetNowString()
{
GetNow();
return now.ToString("yyyy-MM-dd HH:mm:ss.ff");
}
}

class StubDateHelper: DateHelper
{
protected override DateTime GetNow()
{
return now;
}

public void SetNow(DateTime datetime)
{
now = datetime;
}
}

撰寫測試

1
2
3
4
5
6
7
8
9
10
[TestMethod]
public void GetNowString()
{
StubDateHelper dateHelper = new StubDateHelper();
var fakeNow = new DateTime(2017,4,19,20,45,17,880);
dateHelper.SetNow(fakeNow);
string expect = "2017-04-19 20:45:17.88";
string result = dateHelper.GetNowString();
Assert.AreEqual(expect, result);
}

解析

基本上這樣就可以測試了,
原來的代碼,經過一定的重構,
透過virtual方法GetNow,
Datetime.Now作了隔離
適當利用假類別,取代掉GetNow的方法。

這樣夠好了,但是我們可以看看另一種作法

版本3

先看看我們的DateHelper,
在這裡我們將GetNow交由IDateProvider的類別去實作,
如此一來就斷開了耦合性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DateHelper
{
private IDateProvider DateProvider;

public DateHelper(IDateProvider dateProvider)
{
this.DateProvider = dateProvider;
}

public string GetNowString()
{
var now = this.DateProvider.GetNow();
return now.ToString("yyyy-MM-dd HH:mm:ss.ff");
}
}

實作IDateProvider的類別,
在這裡其實不重要.

1
2
3
4
5
6
7
public class DateProviderV1 : IDateProvider
{
public DateTime GetNow()
{
return DateTime.Now;
}
}

讓我們看看測試,
在這裡我們透過一個假的IDateProvider的實作DateProviderStub,
完成了測試,
IDateProvider將DateTime.Now作了隔離,
並且提供更容易修改的假物件(僅僅需要實作觀注的方法即可,不用擔心繼承帶來的附作用)

1
2
3
4
5
6
7
8
9
10
[TestMethod]
public void GetNowString()
{
DateProviderStub dateProvider = new DateProviderStub();
dateProvider.now = new DateTime(2017, 4, 19, 20, 45, 17, 880);
var dateHelper = new DateHelper(dateProvider);
string expect = "2017-04-19 20:45:17.88";
string result = dateHelper.GetNowString();
Assert.AreEqual(expect, result);
}
1
2
3
4
5
6
7
8
public class DateProviderStub : IDateProvider
{
public DateTime now;
public DateTime GetNow()
{
return now;
}
}

圖例解析

我們剛剛究竟幹了什麼?

看看原本的情況,本來的方法因為相依與Datetime而無法測試

讓我們開始下刀,
先用一個新的方法GetNow
將它與待測的方法作分割,
但是對整個類來說仍舊是耦合。

繼續把這刀往下切,
我們墊一層介面,
待測方法不再直接呼叫GetNow
而是透過介面執行,當然會有額外實作介面與注入的功(請參考程式碼,不在此處繪出了.)

最後,別忘了我們的目的
測試原本的待測方法,
我們可以透過一個假的類,
來操控他的行為(ex:凍結時間).
如此一來,就可進行測試了.

另外,這種被待測方法呼叫後
會回傳一個假值的方法或類
被叫作STUB

案例三、發送郵件

事先聲明,這題沒有程式碼,
有興趣實作的人可以試試看.
如果可以分享實作後的資訊給我更好XD

Q:註冊發送郵件如何寫單元測試?

解析
很明顯的發送郵件需要依賴外部的郵件系統,
這裡就會有耦合性,我們可以參考案例2的方式解耦
不過發送郵件並不會有回傳值,
我們要如何驗証正確性呢?

A:檢查調用次數、參數

圖例解析
在案例2的單元測試,
我們透過STUB偽造的回傳值完成測試
並執行驗証.
但是在沒有回傳的值的方法中(被稱作MOCK)
我們只能透過傳遞的參數(如果有多載)
與方法被調用的次數來進行驗証。

重點摘要

  • 單元測試要能清楚表達測試的目的(達意)
    • 命名
    • 減少意外的細節
  • 單元測試一次只作一件事
  • new 本身就是一種邏輯 一種偶合
  • static 是一種高偶合
  • 繼承也是高偶合,能使用繼承的情境很少
    • A is a B 通常只有這種情境才適合繼承
  • STUB & MOCK
    • STUB 會有回傳值,可以在 Unit Test 作驗証(ASSERT)
    • MOCK 沒有回傳值,可以在 MOCK 本身中 作驗証(ASSERT)

其它

  • SLIM
  • 注入相依的幾種方式
    • Pool
    • Constructor
    • Property
  • 書單 : XUnit Test Patterns

直播影片

如果連結失效,煩請告知.

文章內容如有謬誤,煩請指正.

(fin)

[閱讀筆記]其實,你不是沒有時間

六個工具與餐盤

  • 原則:工具簡單至上
  • 面對突發狀況
  1. 月計劃表 (google calendar)
    • 與自已約會(保留給自已的時間)^註1^
    • 工作與私人不要分開
    • 日期與期限
  2. Todo List (inbox)
    • 提醒與集中管理
    • 每天都要檢查一遍^註2^
  3. 日計劃表 (google calendar)
    • 當日約會 & 活動清單
    • 活動清單是你當天的籌碼 也是出現突發
  4. 隨手記 (筆記本&Evernote)
    • 接受任務,再轉到其他工具之中^註3^
  5. 隨身資料庫 (google drive)
    • 將整理過的資料封存在隨手可得的地方
      ex: 上課或分享的簡報、 專案記錄等…有大量圖片、文件等
  6. 溝通工具 (line & slack)
    • 一天檢查電子郵件3~6次就夠了

把時間變空間(視覺化)

  • 個人、家庭、工作取得平衡
  • 安排30分鐘規劃一天的活動
    • 創造性活動安排在精力最佳的時段
    • 安排獨處的時間
    • 安排恢復精力的時間
    • 預留時間給可能發生的突發事件
  • 將所有的事情分為紅綠黃(灰)^註4^,綠色應該越多越好,灰色越少越好。
    6 am7 am8 am9 am10 am11 am12 am1 pm
    5 am本日活動隨手記2 pm
    4 am3 pm
    3 am4 pm
    2 am5 pm
    1 am12 am11 pm10 pm9 pm8 pm7 pm6 pm

應變執行,計劃趕不上變化

  • 調整事情的順序
  • 養成習慣
  • 臨機應變
  • 小心多工
  • 保留風格

  1. 分別為聖的時間,請參考與時間作朋友
  2. 利用分別為聖的時間檢查
  3. 餐盤中間的區塊可以用來作當日的活動清單 & 隨手記
  4. 可以參考四象限 重要-緊急(紅)、不重要-緊急(黃)、重要-不緊急(綠)、不重要-不緊急(灰)

(fin)

自動化 Trello 操作

Trello 是一個非常方便的工作管理工具,
最主要的功能只有 Boards 、 Lists 與 Cards,
確可以發揮相當大的綜效功能,
用來當作敏捷開發的白板、安排工作項目與進度,
作為協作的平台與工具。
也有相當多元的外掛可以供不同的情境使用,
開發人員也可以自行串接API與系統作整合。
簡單記錄自動化產生 Cards 的兩種方法。

第一種方法,使用mail

  1. 開啟 Menu > More
  2. 點選 Email-to-board Settings
  3. 選擇你要產生卡片的 List 與 位置(頂部或底部)

  1. 寄信,信件格式如下
    • email 的 subject 會成為卡片的標題
    • email 的內容會成為卡片的描述
    • 如果有附加檔案在郵件中,會附加到卡片中
    • 在 subject 加入 #label 可以在卡片加入標籤(Labels)
    • 在 subject 加入 @member 可以在卡片加入成員(Members)

更多請參考.

第二種方法,使用API

  1. 登入 Trello
  2. 連線 https://developers.trello.com
    點選Get your Application Key. 連線到 https://trello.com/app-key

取得Key

生成Token


點選allow後,就會顯示你的token,特別注意登入的身份權限,
並且千萬不要外洩你的token與key值。

試打API,建立一張 Card 到指定的 List 中.
並且設定期限(due)與標籤(labels),
更多的API設定請參考.

分析

  • Email:
    • 優點:簡單、方便、可以結合mail system 、附加檔案簡單
    • 缺點:部份功能無法實現(ex: 設定due date)
  • API:
    • 優點:靈活、Resful的API可以實現大部份的功能
    • 缺點:實作比較麻煩

(fin)

ASP.NET Thread Pool 監控

前情提要

上一次說明了 .NET Thread Pool 的機制如何影響 Redis,
.NET Thread Pool 的機制會貫穿任何與它互動的系統或服務,
所以這篇會簡單描述如何對 .NET Thread Pool 建立監控

步驟

  1. 建立監控記數器
  2. 在系統寫入監控數值
  3. 開啟效能計數器

建立監控記數器

記數器 說明
Available Worker Threads 目前在 thread-pool 可以使用的 worker threads
Available IO Threads 目前在 thread-pool 可以使用的 I/O threads
Max Worker Threads 最大可以建立的 worker threads 數量
Max IO Threads 最大可以建立的 I/O threads 數量

建立一個 Console 應用程式

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
using System;
using System.Diagnostics;

class MyAspNetThreadCounters
{
[STAThread]
static void Main(string[] args)
{
CreateCounters();
Console.WriteLine("MyAspNetThreadCounters performance counter category " +
"is created. [Press Enter]");
Console.ReadLine();
}

public static void CreateCounters()
{
CounterCreationDataCollection col =
new CounterCreationDataCollection();

// Create custom counter objects
CounterCreationData counter1 = new CounterCreationData();
counter1.CounterName = "Available Worker Threads";
counter1.CounterHelp = "The difference between the maximum number " +
"of thread pool worker threads and the " +
"number currently active.";
counter1.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter2 = new CounterCreationData();
counter2.CounterName = "Available IO Threads";
counter2.CounterHelp = "The difference between the maximum number of " +
"thread pool IO threads and the number "+
"currently active.";
counter2.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter3 = new CounterCreationData();
counter3.CounterName = "Max Worker Threads";
counter3.CounterHelp = "The number of requests to the thread pool "+
"that can be active concurrently. All "+
"requests above that number remain queued until " +
"thread pool worker threads become available.";
counter3.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter4 = new CounterCreationData();
counter4.CounterName = "Max IO Threads";
counter4.CounterHelp = "The number of requests to the thread pool " +
"that can be active concurrently. All "+
"requests above that number remain queued until " +
"thread pool IO threads become available.";
counter4.CounterType = PerformanceCounterType.NumberOfItems32;

// Add custom counter objects to CounterCreationDataCollection.
col.Add(counter1);
col.Add(counter2);
col.Add(counter3);
col.Add(counter4);
// delete the category if it already exists
if(PerformanceCounterCategory.Exists("MyAspNetThreadCounters"))
{
PerformanceCounterCategory.Delete("MyAspNetThreadCounters");
}
// bind the counters to the PerformanceCounterCategory
PerformanceCounterCategory category =
PerformanceCounterCategory.Create("MyAspNetThreadCounters",
"", col);
}
}

編譯後並執行即可,
執行 regedit 開啟登錄編輯程式,
輸入機碼 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
將可以找到剛剛建立的 MyAspNetThreadCounters 記數器

在系統寫入監控數值

在站台的 Global.asax 加入以下的程式碼

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public bool MonitorThreadPoolEnabled = true;

protected void Application_Start(Object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(RefreshCounters));
t.Start();
}

public void RefreshCounters()
{
while (MonitorThreadPoolEnabled)
{
ASPNETThreadInfo t = GetThreadInfo();
ShowPerfCounters(t);
System.Threading.Thread.Sleep(500);
}
}

protected void Application_End(Object sender, EventArgs e)
{
MonitorThreadPoolEnabled = false;
}

public struct ASPNETThreadInfo
{
public int MaxWorkerThreads;
public int MaxIOThreads;
public int MinFreeThreads;
public int MinLocalRequestFreeThreads;
public int AvailableWorkerThreads;
public int AvailableIOThreads;

public bool Equals(ASPNETThreadInfo other)
{
return (
MaxWorkerThreads == other.MaxWorkerThreads &&
MaxIOThreads == other.MaxIOThreads &&
MinFreeThreads == other.MinFreeThreads &&
MinLocalRequestFreeThreads == other.MinLocalRequestFreeThreads &&
AvailableWorkerThreads == other.AvailableWorkerThreads &&
AvailableIOThreads == other.AvailableIOThreads
);
}
}

public ASPNETThreadInfo GetThreadInfo()
{
// use ThreadPool to get the current status
int availableWorker, availableIO;
int maxWorker, maxIO;

ThreadPool.GetAvailableThreads( out availableWorker, out availableIO);
ThreadPool.GetMaxThreads(out maxWorker, out maxIO);

ASPNETThreadInfo threadInfo;
threadInfo.AvailableWorkerThreads = (Int16)availableWorker;
threadInfo.AvailableIOThreads = (Int16)availableIO;
threadInfo.MaxWorkerThreads = (Int16)maxWorker;
threadInfo.MaxIOThreads = (Int16)maxIO;
// hard code for now; could get this from machine.config
threadInfo.MinFreeThreads = 8;
threadInfo.MinLocalRequestFreeThreads = 4;
return threadInfo;
}

public void ShowPerfCounters(ASPNETThreadInfo t)
{

// get an instance of our Available Worker Threads counter
PerformanceCounter counter1 = new PerformanceCounter();
counter1.CategoryName = "MyAspNetThreadCounters";
counter1.CounterName = "Available Worker Threads";
counter1.ReadOnly = false;

// set the value of the counter
counter1.RawValue = t.AvailableWorkerThreads;
counter1.Close();

// repeat for other counters

PerformanceCounter counter2 = new PerformanceCounter();
counter2.CategoryName = "MyAspNetThreadCounters";
counter2.CounterName = "Available IO Threads";
counter2.ReadOnly = false;
counter2.RawValue = t.AvailableIOThreads;
counter2.Close();

PerformanceCounter counter3 = new PerformanceCounter();
counter3.CategoryName = "MyAspNetThreadCounters";
counter3.CounterName = "Max Worker Threads";
counter3.ReadOnly = false;
counter3.RawValue = t.MaxWorkerThreads;
counter3.Close();

PerformanceCounter counter4 = new PerformanceCounter();
counter4.CategoryName = "MyAspNetThreadCounters";
counter4.CounterName = "Max IO Threads";
counter4.ReadOnly = false;
counter4.RawValue = t.MaxIOThreads;
counter4.Close();
}

當你的站台重新啟動後,
就會定期將 Worker Thread 與 I/O Threads 的監控數值傳遞給系統。

開啟效能計數器

  1. 執行 perfmon.exe 開啟效能計數器
  2. 新增效能計數器(點選綠色加符號)
  3. 選取前面所建立監控記數器就能看到當前 ThreadPool 的使用狀況。
    開啟效能計數器

(fin)

IIS Tracing Log 設定

緣由

當你需要Trace送到IIS的每個Request的細節(包含在pipe line各個模組之間的input/output 與 傳入的參數、header等…),
可以透過開啟tracing log來作追蹤

環境

  1. Windows Server 2012 R2
  2. IIS 8.5.9600.16384

開啟 tracing log

  1. 新增 Tracing Rules

  1. 開啟網站 Tracing 功能

調整 IE Security 層級

  1. 使用 IE 開啟 Log,因 Security 設定無法套用版型

  2. 調整ie enhanced security

  1. 開啟IE > 點選小齒輪,選擇 Internet Options > 點選 Security 頁籤 > 將 Internet 的 Security Level 調整為 Medium-high

  2. 完成

(fin)

CI/CD 環境建置筆記 - 使用Openshift 的 Jenkins (失敗)

前情提要

操作記錄(失敗)

目標:

  • 在 Openshift 新增一個 Jenkins Server

失敗原因:

  • 我找不到方法在 Openshift 上建置的 Jenkins Server

記錄:

  1. 登入OpenShift的web console
  2. Add Application 選擇 Jenkins Server,使用預設設定Create Application.
    Public URL 設定為 http://jenkins-youraccount.rhcloud.com
  3. 連線進 http://jenkins-youraccount.rhcloud.com 會發現需要帳密登入
  4. 取得帳號密碼
    1. 使用 SSH 連線 Openshift 的 Jenkins Server (可以在web console 查到連結)
      > ssh 4263*****************@jenkins-youraccount.rhcloud.com
    2. 查看以下兩個檔案可以取得帳號密碼
      JENKINS_USERNAME
      JENKINS_PASSWORD
  1. 登入後,管理 Jenkins > 設定系統

    1. 將執行程式數量設定為 1
  2. 選擇新增作業

    1. 第一步要將原始碼自Github pull下來;在原始碼管理選擇Git , 設定好RepositoriesBranches to build
  3. 執行一次建置,這個步驟是為了產生work space 。

  4. SSH 連線 Openshift,切換目錄到你的專案的work space
    > ssh 4263*****************@jenkins-youraccount.rhcloud.com
    > cd app-root/data/workspace/your_project_name

  5. 檢查一下目前Git的遠端Repo有哪些
    > git remote -v

  6. 將Openshift上的nodejs應用程式repo設為remote
    >git remote add openshift ssh://5**********************@nodejs-youraccount.rhcloud.com/~/git/nodejs.git/

  7. 推送到openshift remote
    失敗!!原因是權限問題,Openshift remote 是透過 SSH 連線,
    在認証公鑰的過程中,需要寫入 ~/.ssh/known_hosts 檔案。
    但是 Openshift 建立的 Jenkins Server 登入帳號,權限並不足以寫入而造成失敗

(fin)

CI/CD 環境建置筆記(一) - 在 windows 安裝 Jenkins

前情提要

操作記錄

  1. 下載並安裝Jenkins(記錄版本為2.32.1)

  2. 連線localhost:8080,會要求輸入Administrator password

  3. 安裝Plugins(這裡選擇預設)

  1. 安裝畫面

  2. 建立管理者帳號密碼

  3. 登入後,管理 Jenkins > 設定系統

    1. 將執行程式數量設定為 1 (安裝完預設為2,其實可以不用修改)
    2. Shell 設定為 C:\Windows\system32\cmd.exe
  4. 建立第一個作業,選擇新增作業 > 輸入作業名稱 ,選擇「建立多重設定專案」

  5. 執行一次建置,這個步驟是為了產生work space 。
    work space 路徑大致如下 .\Jenkins\workspace\Project name

  6. 執行 console 並切換路徑至 work space

  7. 將 Openshift 上的 nodejs 應用程式 repo 設為 remote
    >git remote add prod ssh://5**********************@nodejs-youraccount.rhcloud.com/~/git/nodejs.git/

  8. 回到Jenkins,作業 > 組態 > 建置 > 新增「執行Windows批次指令」

    1
    2
    3
    REM 測試
    whoami
    git push prod HEAD^:master
    1. 額外處理事項:
      直接在 Jenkins server 發 pr 給 openshift 時,發生 503 錯誤。
      使用 ssh 登入 openshift 看 log ,發現
      Node Sass does not yet support your current environment 錯誤
      必須登入執行以下語法修正模組問題 npm rebuild node-sass
  9. 建置作業,會得到錯誤訊息

    1
    2
    3
    4
    上略...
    19:44:46 Host key verification failed.
    19:44:46 fatal: Could not read from remote repository.
    下略...

原因:主機密鑰驗證失敗,這個錯誤的意思是我的 Jenkins Server 主機並不認得遠端的 Openshift Server 的 host key,主要的原因是 Jenkins Service 在執行的身份是 NT AUTHORITY\SYSTEM,由於我已經有合適權限的帳號,所以只需要切換執行 Jenkins Server 的身份即可。

如果你尚未建立遠端ssh連線的存取權限,或是對ssh連線不熟悉,可以參考文末的參考聯結。

參考

(fin)

CI/CD 環境建置筆記 - 前言<目的>

現有架構

版本控制

  1. Github
  2. Openshift
    Openshift 是實際線上服務所在,也可以稱作是我的產品(Product),
    Github 則是單純的負責版本控制。

    開發流程

    作為獨立開發的專案,這個網站只是我很單純的自我介紹、練習(KATA)、學習與分享的集散地。
    原本的開發流程很單純,如上圖。完成的CODE同步到 GITHUB 後也同步上 Openshift ,
    這樣的流程雖然簡單,但是每次都要人工執行,因為其執行順序,其實都隱含著風險,
    例如:上錯版本或是產品未進版控等等…,
    而當進一步想要執行建置、編譯 、套件管理、測試、分析與產生報表時,
    產品與源碼將會產生差異(ex:產品會包含壓縮的檔案而源碼則是未壓縮的檔案)

缺點:

  1. 在這樣的架構上容易不小心發佈還在開發中的功能。
  2. Prod的來源就是程式碼,無法確保與版控一致,如此就喪失版控的用意。
  3. 難以擴展其他功能,如:建置、編譯 、套件管理、測試、分析與產生報表

目標:


如圖所示,
第一步 Jenkins要將原始碼自Github pull下來
第二到第N步 Jenkins要執行建置、測試、coding style的檢查、壓縮…等等。
最後一步 Jenkins 將會將程式碼發佈到Openshift 上面。
中間的步驟先跳過,之後再一一補上。
所以第一目標很簡單,
從Github Pull再Push到Openshift。

[記錄]VS2015 StyleCop 誤判SA0102

環境

  • 作業系統:Windows 10
  • 開發工具:Visual Studio 2015 (Professional ver14.0.25431.01 Update 3)
  • StyleCop 4.7.50.0

情境

當使用C# 6 的INTERPOLATION STRING組合字串時,在StyleCop 4.7會誤判並回報SA0102的警告。

1
2
3
4
5
6
return new ExcelResult
{
Data = exportData,
FileName = $"{shopId}_Code_{DateTime.Now.ToString("yyyyMMddHHmm")}",
SheetName = "ECouponCode"
};

修正目標

  1. 將 StyleCop 4.7 更新至 StyleCop 5.0
  2. 編輯客製化的StyleCop Rules(直接將4.7的設定檔覆蓋VS會報錯)

修正記錄

  1. 移除 StyleCop
    控制台 > 新增移除程式

  2. 移除 Visual Studio 上的 StyleCop
    工具 > 擴充功能和更新

  3. 自你的程式碼移除所有對StyleCop的參考
    我的程式碼中並不包含對StyleCop的參考,故略過此步驟

  4. 搜尋StyleCop*.dll 並且移除(非必要)

  5. 重新安裝 StyleCop Visual Studio Extension

    1. 安裝完成檢視安裝記錄檔

    2. 可以透過安裝記錄檔取得安裝路徑

  1. 客製修改StyleCop設定檔
    5-2的步驟可以找到Settings子資料夾,內含預設StyleCop設定檔,
    複制這個檔案到上一層,重新命名為Settings.StyleCop,
    透過StyleCop.SettingsEditor開啟Settings.StyleCop調整設定值。

參考

(fin)

[閱讀筆記]把時間當作朋友

零、困境

✖ 時間無法管理 能管理的只有你自已。

一、醒悟

  • ✖ 用思考控制思考
  • ✖ 心智:就是心靈的智慧,用理性處理感性,控制情緒與慾望。
  • ✖ 人會在相同的情況下作出完全相反的結論

…歷史上也常常出現這種情況——其實目的都是“為了人類更好的明天”,可偏偏出現了對立的兩派人,
他們為了原本一模一樣的理想爭執不休,甚至“拋頭顱”、“撒熱血”,犧牲幾代人的福祉。

比如,所謂“水火不相容”的“社會主義陣營”和“資本主義陣營”。
看穿這一切,擺脫自己的局限,需要心智的力量。

二、現實

  • 速成絕無可能
  • 交換才是硬道理
  • 完美永不存在
  • 未知永遠存在

未知分為兩種:一種是永遠不能解決的,另一種是在可預見的未來也許能夠解決的。
✖ 吾生也有涯,而知也無涯。以有涯隨無涯,殆已!已而為知者,殆而已矣!…指窮於為薪,火傳也,不知其盡也。–莊子。養生主
✖ 站在巨人的肩膀上

  • 現狀無法馬上擺脫

接受現狀才是最優策略——有什麼做什麼,有什麼用什麼;做什麼都做好,用什麼都用好。
不要常常覺得苦(這會讓人忍不住顧影自憐,浪費精力與時間),而要想辦法在任何情況下找到情趣——
——快樂是一種本事

心懷“夢想”的時間越長,它的沉沒成本就越高。

✖ 積沙成塔,滴水穿石,時間可以累積,也可以消耗。

  • 與時間做朋友

與時間做朋友的方法很簡單:用正確的方法做正確的事情。

儘管現實總是如此難於接受,堅強的你卻應該坦然。以上提到的種種現實,包括“速成絕無可能”、“只有付出才有收穫”、“完美永不存在”、“未知永遠存在”、“現狀無法馬上擺脫”,都既清楚又簡單,你必須要接受——不僅要接受,還要牢記;不僅要牢記,還要堅信,不容半點動搖。最好時常把自己的一些念頭記下來,然後與這幾條現實對照,看看它們是否與這些現實相符。

時間是現實的人的朋友,是不現實的人的敵人。時間不是故意要這樣做,只不過事實如此。

✖ 正確的事,正確的做 ; 首先要學會判斷什麼是正確的事。

三、管理

  • 估算時間

分辨任務的屬性——它是熟悉的還是陌生的呢?

對學習來說,任務“陌生”的可能性更大,因為學習本身是一個探索未知的過程。完成學習任務常常需要花費比我們想像中多得多的時間。對工作來說,任務“熟悉”的可能性更大。因為工作本身是一個應用已知的過程。

✖ 軟體工作的這個行業,很有可能是大多數是未知的情況。

  • 及時行動

接受任務之後,什麼時候開始執行才好呢?比“越早開始越好”更切實的答案是“現在就開始”。

✖ ASAP 不是一個好答案 NOW 才是。

✖ 不求有功,但求無過是種慢性自殺,滴水穿石—會消磨掉你的累積。

  • 直面困難

效率低下的根本原因是什麼?答案是:迴避困難。
……
……這些問題都源自同一個習慣:專做簡單的,迴避困難的。

  • 關注步驟

所謂“三思而行”在我看來就是指做任何事情之前都要考慮相關的3個方面:內容(What)、原因(Why)、方法(How)。任何任務都起碼具備3個屬性:何事(What)、何因(Why)、何法(How)。

不停地細分、拆解任務,而且越具體越好,直至每個小任務都可以由一個人獨立完成。

例子

擴充詞彙量→托福詞彙→托福核心詞彙→21個單元→每個單元大約100 個單詞→一個單元分2次完成……
▷ 先嘗試做一兩個階段,測量一下完成一個階段需要多長時間。
▷ 按照測量的結果製作一個時間表,把其餘若干個階段所需要的時間填寫完整(最終總是需要做一些調整的)。
▷ 背單詞需要重複,所以,每3個階段過後要留出與完成1個階段相等的時間去複習。這就意味著一共需要花費完成56(42+14)個階段的時間。
▷ 每完成總任務的1/3,就增加與完成1個階段相等的再复習時間。這就意味著一共需要花費完成59(56+3)個階段的時間。
▷ 學習過程中可能需要多次快速重複記憶,每次可能相當於完成3~5個階段所需要的時間。由於熟悉程度的不斷增加,每次重複記憶所需要的時間會越來越短,所以,預計進行3次重複記憶需要相當於10個階段的時間。這就意味著一共需要花費完成69(59+10)個階段的時間。

完成每個階段的具體步驟。

▷ 每天早晨騰出一點時間。
▷ 把前一天背過的單詞朗讀至少2 遍。
▷ 聽錄音,跟讀當天要背的單詞3~5遍,主要關注發音、拼寫,順帶看看詞義,能記多少就記多少,不求速成。
▷ 上午利用閒暇時間通讀詞彙列表,並反复閱讀例句。
▷ 下午用專門的時間把當天要背的單詞集中背2~3遍。可以一邊讀,一邊抄,一邊背,不要只是坐在那里呆呆地盯著詞彙看。
▷ 空閒的時候反复聽當天要背的單詞,重複次數越多越好。
▷ 晚上睡覺前複習當天背的單詞。

  • 並行串行

✖ 拆分細項,尋找並行的可能。

華羅庚先生曾經用燒水泡茶為例說明過這個問題。

燒水泡茶:參見《統籌方法平話及補充》,華羅庚著,中國工業出版社,1966。
▷ 辦法甲:洗好水壺,灌上涼水,放在火上。在等待水開的時候洗茶壺、洗茶杯、拿茶葉。等到水開,泡茶喝。
▷ 辦法乙:先做好一些準備工作,包括洗水壺、洗壺杯、拿茶葉。一切就緒,灌水、燒水,坐待水開了泡茶喝。
▷ 辦法丙:洗淨開壺,灌上涼水,放在火上,坐待水開。水開了之後急急忙忙找茶葉、洗茶壺、茶杯,泡茶喝。

✖ 分別為聖的*時間片***

一個處理器在一個時間段內其實只能做一件事,因為它只有一個個體、一個時空。而多任務操作系統把一個長時間段劃分成很多短小的時間片,每個時間片只讓處理器執行一個進程(Process)——儘管同時可能有多個進程需要處理。在第一個時間片裡,操作系統讓處理器處理A進程;時間片的時間用完之後,無論A進程處理到什麼程度,都要被“掛起”(即,A進程這時不能再佔用處理器資源——儘管它還是被允許使用計算機的其他資源,如內存、磁盤、屏幕輸出等);在第二個時間片裡,處理器處理的是B進程,時間用完之後,B進程將與A進程一樣被中途“掛起”;

  • 感知時間

逃避責任就會帶來輕鬆,可那恰恰就是“生命中不能承受之輕”啊!

有的時候「逃避雖可恥但有用」,學會判斷什麼是可以逃避的事,什麼是不可逃避的事。

學著做每天的“事件日誌”(Event Log)。除了自己經歷的事件之外,
一概不記,而且盡量不記感想,不記感受,只記錄事件本身。

…記錄過程要比基於結果的記錄更為詳盡

例子

烏里揚諾夫斯克。一九六四年四月七日。分類昆蟲學(畫兩張無名袋蛾的圖)——三小時十五分。鑑定袋蛾——二十分(1.0)。

附加工作:給斯拉瓦寫信——二小時四十五分(0.5)。

社會工作:植物保護小組開會——二小時二十五分。休息:給伊戈爾寫信——十分;
《烏里揚諾夫斯克真理報》——十分;列夫·托爾斯泰的《塞瓦斯托波爾紀事》——一小時二十五分。

基本工作合計——六小時二十分。

✖ 簡單的分類 + 事件 + 費時,最後再合計起來。
(其於事實)條列式的記錄法,與時間調色盤(預定)的方法不太一樣。
你可以預定你要作的事,可是你無法正確的估時 ; 這是事實,請面對這個事實。
輔助上分別為聖的時間切片或許可以有所幫助

  • 記錄開銷

練習中

  • 制訂預算

✖ 先養成記錄的習慣,再養成制定預算的習慣
✖ 只列事情,重要/不重要

每個人都喜歡做有趣的事情,做的時候往往並不關心這件事到底有沒有用。可是,有趣的事不見得有用啊!

養成任何一個哪怕很小的習慣都需要掙扎。然而,貌似痛苦的掙扎過程,在將來的某個時刻終將變得其樂無窮。

  • 計劃

計劃成功的前提:目標現實可行

我們不是計劃著失敗,而是失敗地計劃(People don’t plan to fail, they fail to plan)。

✖ 簡單的判斷目標是不是現實可行

證明我的目標現實可行的方法比較簡單:

  1. 已經有人做到了。
  2. 我與那個人沒有太大的差距。

長期計劃是需要通過實踐才能習得的能力

沒有人能給我做職業規劃。…生活本身充滿了意外,並且,總是意外到無以復加的地步。

✖ 先從記錄開始,持續一周,繼續保持記錄下試著開始分配時間。
✖ 再試著從周計劃開始作規劃,練習並且保持。

計劃固然重要,行動更為重要。

任何事情,都可能經歷相同的過程:逐步熟悉,小心摸索,失敗、失敗、再失敗,
認真反思,捲土重來,直至成功。而最初,在我們對任務連基本的認知都沒有的時候,
制定出來的計劃十有八九隻不過是空談。

  • 列表

  • 流程

✖ 預想各種可能的情境,不用一次到位,持續整合的重點在持續。

範例:

▷ 確定對方最可能方便接電話的時間(難以確定的時候先發短信詢問)。
▷ 在撥打電話甚至發短信詢問對方是否方便之前準備好一切計劃溝通的內容,作好檢查列表放在手邊,確保溝通過程中不會遺漏要點。
▷ 通話前把重要信息整理成電子文本,在通話中做必要的更新,通話結束後,馬上通過電子郵件將備忘發送給對方。
▷ 若對方沒有接電話,則給對方發署名短信告知詳細事由, 並做好記錄,防止自己遺忘此次溝通任務。
▷ ……

  • 預演

準備不足,所以害怕。

✖ 類似一種沙箱測試,讓錯誤發生在測試階段。

  • 驗收

向自己提出一個問題並要想辦法回答清楚:“怎樣才算’做好’?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
本篇心得: 這是需要實際操作的一篇,仍在實踐中。
首先是記錄自已的時間花在哪裡?
再來是制定時間的預算,分別出神聖的時間去累積一些東西(ex:學習英文、跑步);
當習慣養成,就不再困難了,而是生活的一部份。
同時注意工作的流程,
1. 問自已What Why How ?
2. 儘可能拆解工作流程的步驟到最小化,建立列表。
3. 常常發生的工作要設想各種情境,建立 SOP 以縮短時間。
4. 陌生的工作可以透過預演來試錯。
5. 一定要驗收。
6. 面對困難與失敗。
7. 及時行動!
8. 及時行動!!
9. 及時行動!!!

四、學習

基本途徑

  • 體驗
  • 觀察
  • 學習

✖ 自由是可以被剝奪的。

經驗局限

日常生活中主要的“溝通障礙”本質上幾乎都是由於溝通雙方無法讓對方理解與他們的經驗相悖的知識或信息造成的。

長期的進化使人類到達了今天這個高度,但是每個人在出生的那一剎那,居然與其他動物站在幾乎同樣的起點上,心智要從零開始進化。

優秀的領導,能夠把人們帶到他們想去的地方;而卓越的領導,能夠把人們帶到他們應該去但是沒想過要去的地方
A leader takes people where they want to go. A great leader takes people where they don’t necessarily want to go,but ought to be.

牢記在這世界上確實存在“與現有經驗相悖的知識”,再把這句話變成經驗,用它去類比未知,而後投入大量的時間和精力去學習和掌握“科學方法論”,掙扎著進化成為真正意義上的“人”。

自學能力

  • 閱讀理解能力 ->檢索能力 -> 寫作能力 -> 實踐能力
  • 永遠保持開放的心態

最好固定一段時間來把那些目前暫時無法理解的、支持的、反對的、無所謂的論點和觀點記錄下來。對無法理解的,寫下自己當時的疑惑何在;對支持的,記錄幾個理由或者實例;對反對的,同樣記錄幾個理由或者實例;甚至對那些無所謂的,也記錄其原因。一個有著這樣良好記錄習慣的人會獲得他人無法擁有的處理信息和知識的能力——“反芻”。這種“反芻”能力是我們避免成為“選擇性輸入”受害者的重要保障。
在學習的時候,進展和時間的關係肯定不是線性的:所謂“一分耕耘,一分收穫”。這個關係曲線更可能是階梯狀的:學習過程中有很長時間一點進展都沒有,但從某一刻開始突飛猛進,而後又是長長的一段所謂的“平台期”。…只有經歷積累的過程,“量變到質變”的效果才會出現,才有可能突飛猛進。

五、思考

勤於思考

人都有大腦,閒置還是使用,是個問題。

  1. 獨立思考
  2. 思考任務的目標、實質、意義

很多人就是這樣,堅持拒絕思考,然後用天下最累的方式生活而不自知。大哲學家羅素曾觀察到這個現象,他為之奇怪並慨嘆,“ 很多人寧願死也不願思考 ”,然後戲謔道,“ 實際上,他們確實死得很快。”

Most people would die sooner than think — in fact they do so.
— Bertrand Russell,In The ABC of Relativity,1925,P.166

思維陷阱

概念不清和拒絕接受不確定性

  1. 概念不清

    學習任何知識最重要的一點,就是搞清楚它所有的基礎概念。

    讀教科書,要先把所有概念都記下來,暫時不懂的就死記硬背。把概念牢記於心,就可以通過以後的學習和實踐反複審視它,並形成透徹理解。

    本書強調“時間不可管理”、“我們只能管理自己”,並非咬文嚼字。“時間管理”和“自我管理”是完全不同的概念——焦點不同,方法不同,效果不同

  2. 拒絕接受不確定性

未知永遠存在。從本質上來看,不確定性和未知是一回事。

因果關係

基礎

外因會影響內因,內因同樣會影響外因。它們相互影響,互為因果。

舉一個特別好玩的現象為例:在某種意義上,學生的水平決定教師的水平。

這話並沒有說反。師生之間的有效溝通,肯定不僅是教師單方面的灌輸。越是用心的教師,越關注學生的反饋;越是用心的學生,越關注教師對他的反饋的反饋。顯然,這種溝通不僅是雙向的,還隨著雙方的用心程度而不斷增強。

這和下棋是一樣的道理。據說,棋藝到了一定程度,棋手就會不由自主地挑選對手,因為跟高手下棋就會進步,但反過來,與“臭手”交手多了,自己的手也會變“臭”……優質的學生,對他們的教師來說,不僅是令人愉悅的教學對象(學生一點就透,老師沒有不開心的),更重要的,他們還是對教師的挑戰——這些學生有著長期而且優秀的學習經驗,也因此擁有相對良好的判斷能力,隨時可能提出一般教師無法回答的問題。經過一段時間的積累,雙方都會因為教學和溝通發生巨大的進步——只要雙方都足夠優秀,足夠用心。

正在塑造我們的這個環境,也是我們自己(參與)塑造的

要做一個用心的人,要用心做事,因為這世界其實也是有“心”的

雙盲測試

註: 受測者不知道安慰劑的存在,測試者則不知道誰服用了安慰劑,單純以局外人的角度觀測記錄。

人群中也有差不多⅓的人更易受到(來自他人或來自自身的)心理暗示的影響。也就是說,他們更可能在服用安慰劑後病情真正好轉。

自證預言

莫頓教授用銀行擠兌的例子說明了自證預言的作用機理:

一家銀行本來運作得很正常,但不知什麼原因,出現了“這家銀行要倒閉”的流言。
流言越傳越廣,導致越來越多的人信以為真,有人為防意外而跑到銀行把自己的存款提走。
恐慌情緒蔓延,並且變得愈加真實,更多的人衝進銀行提走自己的存款……最終,擠兌發生了,銀行真的倒閉了。

一個原本並不存在的原因竟然“無中生有”變成了真正的原因。

心中恐惧失敗,才是失敗的原因

逆命題

原命題為真,它的逆命題不一定為真。
P 則 Q 等於 ~Q 則 ~P
但是不一定存在 Q 則 P 的關係
有70%以上的人分不清楚原命題和逆命題之間的區別。

參見《認知心理學》(Cognitive Psychology: A Student’s Handbook,2000),邁克爾·艾森克(Michael W. Eysenck)、馬克·基恩(Mark T. Keane)合著。

✖ 心得: 人很好騙,至少70%很好騙。

舉證責任

“舉證責任”是不對等的
爭論雙方的境況常常處於這種狀態:
▷其中一方肩負沉重的舉證責任(burden of proof)
▷另外一方則享有來自假設的恩惠(benefit of assumption)

既然你無法證明我是錯的,那麼我就是對的。這是一種典型的邏輯錯誤

✖ 套用一下邏輯學:
我是對的 則 你無法証明我是錯的,恒為真。
你無法証明我是錯的 則 我是錯的,恒為真。
你無法證明我是錯的 則 我是對的,不恒為真

案例局限

最為常見的邏輯錯誤就是“以偏概全”——某種經驗在某個人身上應驗了,並不意味著該經驗在所有人身上都會起作用。

✖ 常見的推銷話術,我作得到,你也作得到。努力就會成功。
這類的話術可怕的地方在於它不完全是錯的,但是你必需客觀衡量各種條件,而非局限單一案例。

對立論證

人們可能基於一模一樣的原因做出截然相反的決定。換句話說,用同樣的論據證明截然相反的論點。

抱怨上司“愚蠢”的人和能夠發覺“上司的愚蠢可能有另外的解釋”的人,得到的結論和採取的行動往往截然相反。因此,時間在他們接下來的經歷中所產生的伴隨作用也截然相反。這裡,時間再一次選擇與心智強大的人做朋友

一旦意識到對立論證的存在,應該“哪一個更合理、更現實就接受哪一個”,而非“哪一個更積極就接受哪一個”,因為後者只是自我欺騙而已。積極的並不總是好的,哪一個極端理想主義者(以及他們的想法、理念)不是積極的呢?

✖ 職場上不論是留下繼續努力,或是掛冠求去都無對錯之分,而是何者更為合理。這個道理在人生的選擇上也是,需要注意對立論證的存在,堅持或放棄本無對錯,合理的判斷即可。

張冠李戴

論點和論據之間儘管全無邏輯聯繫,卻可以用一種“顯然合理”的姿態綁在一起。

舉例:

將字母A到Z分別編上1到26的分數(A=1,B=2,…,Z=26),然後比較不同單詞的分值:
▷Knowledge(知識)得到96分
(11+14+15+23+12+5+4+7+5=96);
▷HardWork(努力)也只得到98分
(8+1+18+4+23+15+18+11=98);
▷Attitude(態度)才能左右你生命的全部,
因為它能得到100分
(1+20+20+9+20+21+4+5=100)——滿分。
得出結論:“態度改變一切”。
Bullshit(胡說八道)
(2+21+12+12+19+8+9+20=103)

感悟與道理

“道理”應該是普適的,而“感悟”只來自個體經驗。

並非只有專家級別的新聞工作者才要分清“看法與事實之間的區別”,其實每個人都需要清楚地認識“道理”和“感悟”之間的巨大差異。

如果某個人把他們說的當作全部,把他們沒說的當作沒有,那麼這個人的智商就跟寓言中那個掩耳盜鈴的傢伙屬於同一個水平了。

人類普遍擁有的一個認知偏差就是:把成功攬到自己身上,把失敗歸咎於別人或者壞運氣。(這在心理學上有個術語,叫做“自利性偏差(Self-servingBias)”。)從這裡我們就可以知道,那些“成功者”這麼做的時候,往往並不是有意欺騙——他們甚至出於好意。

一個很實用的建議:與其關注成功者,不妨反其道而行之——努力從失敗者身上汲取經驗。

✖ 困難的點在於,感悟難以作”雙盲測試”,也深受”案例局限”與”安慰劑效應”影響。

克服恐懼

“道理都明白,可就做不到”

輔助工具

語言

以下一些句式最好經常使用,因為它們特別有助於獨立思考習慣的養成,並且也有刺激思考的作用:
▷……是一回事,而……是另外一回事。
▷……和……其實根本不是一回事。
▷……不一定……
▷……。可是,這並不意味著……
▷……也許還有另外一種可能性(解釋)。
▷……看起來像……,可是……
▷……。而事實卻可能遠比看起來的更為複雜(簡單)。
▷……。然而,(這個論斷)反過來(陳述)卻不一定成立……
▷……其實很可能與……根本就沒有任何關係。
▷……和……之間不一定是單純的因果關係,它們也可能互為因果。
▷……和……之間的比較也許沒有任何意義。
▷……其實不過是表面現象,其背後的本質是……
▷……有一個通常被忽略的前提。
▷……儘管聽起來很有道理,然而卻完全不現實。
▷……也許有人會說……,但是這種質疑卻……

要刻意迴避的句子
▷……難道就沒有一點可取之處嗎?
▷……要是……就好了!

六、交流

學會傾聽

為了真正做到有效傾聽,最需要克制的就是“過早質疑”。

就算需要質疑,也一定要等到對方把話說完。

說與不說

“知無不言,言無不盡”在大部分情況下是最浪費時間和精力的做法。

…在分辨談話對象之前很可能要先分辨自己,所以,
“可與言而不與言,失人。不可與言而與之言,失言。”這是說要分辨談話的對象。

共生狀態

見瓦茨拉夫·哈維爾先生製定的《對話守則》:
1.對話的目的是尋求真理,不是為了鬥爭。
2.不做人身攻擊。
3.保持主題。
4.辯論時要用證據。
5.不要堅持錯誤不改。
6.要分清對話與只准自己講話的區別。
7.對話要有記錄。
8.盡量理解對方。

雙方想要進行有意義的討論,最基本的要求就是雙方必須共同遵守“理性討論基本原則”。

跨越“自以為是”

✖ 「緣督以為經;因其故然」— 莊子。養生主 ; 學習應順其自然,不然會把自已累死。「知知為知知,不知為不知,是知也」—論語。

第一個原則:有意義的討論是競合
第二個原則:真理是獨立存在的
第三個原則:真理不變

正確複述

為了保證溝通順利,往往需要添加一個驗證機制,或者說反饋機制。

勤於反思

  • 深刻了解經驗的局限
  • 時時刻刻保持警惕

手裡只有一把錘子,看什麼問題都像釘子

  • 用記錄,使自己能夠記住更多的經驗
  • 通過觀察和閱讀汲取他人的經驗
  • 經常試用類比來跨越未知與已知的障礙
  • 耐心等待以獲得不能跨越時間的經驗

七、應用

興趣

說來說去,是順序出了問題:往往並不是有興趣才能做好,而是做好了才有興趣。人們總是搞錯順序,並對這樣的錯誤毫不知曉。雖然並非絕對,但完成大多數事情,確實都需要熟能生巧。做得多了,自然就能擅長;擅長了,自然就做得比別人好;做得比別人好了,興趣就濃起來了,而後就更喜歡做、更擅長……進入良性循環。可同樣的,做得多,就需要大量的時間投入,所謂“沒興趣”,往往不過是結果,如果將它當作“不去做好”的理由,最終的懲罰就是大量時間白白流逝。

方法

所有學習上的成功,都只依靠兩件事——策略和堅持,而堅持本身就是最重要的策略。堅持,其實就是重複;而重複,說到底就是時間的投入,準確地說,是大量時間的投入。

✖ 你沒有實際作之前,不會知道效果如何,再在找更好的方法之前,最好的策略是堅持。

痛苦 -比較 - 運氣

人脈

當我們把時間花到一個人身上的時候,相當於在他身上傾注了自己生命的一段。

▷專心做可以提升自己的事情,學習並擁有更多、更好的技能,成為一個值得他人交往的人。
▷學會獨善其身,以不給他人製造麻煩為美德,用自己的獨立贏得尊重。

✖ 人必自重而後人重之—你值得人家交往,人家就會來跟你交往。

自卑

✖ 保持謙卑,認識真正的自已。

靈感

✖ 靈感來自於累積,筆記是一個好工具。

鼓勵

效率

節奏

物極必反

  • 絕對不要盲目地試圖減少睡眠時間
  • 盡量不要減少與家庭成員交流的時間
  • 最好不要放棄你的社交時間

自我證明

參考

(fin)