本人不是什麼Scrum講師
所以只談實際發生的事情
而那些高大上的東西
就交給專門的講師們

總體言之
Scrum是一種軟體專案的開發體制
被歸類為敏捷開發方法的一員

如果你要告訴一個阿嬤(或你老闆)
什麼東西是Scrum
那其實從反向去思考比較快

為什麼Scrum和其它敏捷方法誕生了?

我們知道很多解決方案的誕生
是源自於舊的解決方案不完美

如果原來解決方案是好的
那就不需要新的解決方案了

反之新的解決方案如果被如火如荼的討論
代表舊方案有瑕疵
瑕疵越大
反彈力道也會越大越火

所以你老闆如果覺得舊方案很好
那就不要多費唇舌和他提新方案
把時間拿去打電動
做做副業更好

通常你老闆願意試著耐心聽你講新方案
代表他遇見麻煩了
想找個天兵天將來解決

在敏捷方法出現前
就已經有很多軟體系統被寫出來了

他們有些用起來很好 
有的用起來很爛

有些第一版很好 第二版就死了
有些第一版很爛 第二版成功了
更多的是胎死腹中 你永遠都不知道它的存在


在工業革命時
人類發現了比動物能更具效率和可靠的能量運用方式
使得原先手工生產的產品良率和產能大幅提升

於是很多工廠管理學便因此而生
討論如何在相同的投入下得到越大的輸出

而軟體工程相較於工業革命晚了超過100年
所以初期的軟體專案沿用舊的工廠管理方法
是再自然也不過了


比如說要蓋一間房子
先找設計師畫設計圖
房子幾層,多少隔間
電力系統,排水系統
耐震係數,建築容積
相關法律文件申請

然後開始發包建築公司施工
採購原物料,水泥,磚頭,鋼筋

施工現場則有工頭負責監工
有負責綁鋼筋的工人
有負責灌水泥的工人
有負責砌牆的工人
有負責開堆高機的工人
每間房子大致流程都大同小異


這讓批量化的大基建成為可能
預算和金融槓桿風險全部都可以在事前得知


所以傳統的軟體開發到達一定規模
也類似這些傳統產業的分層架構
只是職務名稱可能不同

有業務,有產品經理,有專案經理
有技術長,有技術人員

這些其實就是投資者,經營者,經理,工頭,工人
這樣的分層架構


它的特徵在於任務的派發是從上而下
我們稱之為傳統的瀑布型開發模型

雖然工業革命不過兩百年
但人類的政治體制已經發展了上千年了
這套瀑布型開發模型很多地方可以套用舊有的政治學理論
自然就受到廣大的管理階層的喜愛


剩下的工作就是讓軟體開發像鎖螺絲一樣容易
讓我們到特力屋,買下軟體積木
然後請廉價工人組裝起來吧
鎖螺絲的時間幾百萬上下


但遺憾的
瀑布型管理要能推行無誤必須建立在幾個前提上

1. 投資者需要能準確的預測未來和市場
2. 設計者的設計方案必須準確無誤
3. 工人要能無障礙的理解設計方案

具備這些條件只有一個,那就是全知全能的耶和華上帝
但人不是神,很明顯會犯錯,而且會大大的犯錯

投資者真能準確預測市場,那就去買股票期貨債券黃金
還投資什麼實業呢?那是人類才會做的事
但事實上如果你對市場有超過50%的預測能力,就可以幹掉巴菲特


那下面做事的人更不用提,有這種能力還給你打工嗎?

有些很神的專案管理師和工程師
似乎可以一次性的把產品做好做對
那是因為他們做過很多爛掉的東西
浪費了很多投資人的錢或工程師的肝換來的經驗

做出來的東西與預期不符
推到重做的比比皆是

每次推倒都能做得比前一次好
最後得到我們手上用的軟體

貴!!!
昂貴!!!
雖然最我們拿到想要的東西
但顯然可以用更少的成本得到我們想要的

所以管理者們就這樣想
是不是可以根據前面的失敗
定下一些規定
讓失敗不會重蹈覆轍

於是專案又失敗了
然後定下更多規定
不斷重複到所有人被這些規定壓垮為止

這顯然是哪裡出了問題了

所以敏捷方法應運而生
他告訴老闆們,採用我這套方法可以避免上面的問題


第一
你要接受人不是神會犯錯

第二
人的的肉體和精神能力有限
在靠核子動力活動的完美AI機器人出現前
你還是得靠這些不完美的人類做事


所以糾錯機制和以人為本的軟體開發方式應運而生


迭代機制取代瀑布型方法
讓錯誤可以被提早發現,提早治療
減少一錯再錯成本

讓韭菜們可以自主性參與專案
而非一刀切的專制體制

韭菜雖是韭菜 倒底也是工程師
可以彌補上層的思慮不周
但你要提供機制讓他能夠幫助你
也就是要引入某些民主制度

重點是: "你要提供機制讓他能夠幫助你"

一台波音飛機失事前
下面的維修工人早幾年前就知道哪裡有問題了
但在公司體制下他是不可能見到有決策權的人

就算見到了 提了也不會聽
外行的有決策權 但內行的沒有
在各行業比比皆是

所以必須把權力放出來
讓內行的人去決定
便是敏捷的一大重點

上面鋪陳那麼多
看官們看見問題了嗎?

放權這件事在管理階層眼中簡直要他老命
你要他承認他外行也不可能

把權力放出來,讓內行的人去決定
這件事物理上正確但政治不正確


本文提Scrum在台灣軟體業推行的難度

首先台灣其實並沒有從製造業升級
以鴻海為首的大製造業比比皆是
手上有資金的人思維仍舊老舊

如同戰功彪炳的開國功臣
你比老子打下更多土地再來和我談

推行Scrum和一些敏捷方法
從根本上會衝擊公司的管理和政治架構

所以你需要的不是Scrum,而是辛亥革命
直接蹦掉老闆當新地主快一點

當然這是開玩笑的
阻力大也得推看看 不然怎麼騙錢(誤)

所以有些地方必須玩半套而沒半法全套
比如說故事點數,站立會議

因為這些沒有碰觸到某些人的核心利益
又"看似"可以更好管理工人
不違反傳統瀑布型管理架構

以故事點數來說
我聽說有公司不成文規定不能超過13點(比方說)
因為這樣會打到分析人員
代表他分析不到位,使用者樣例沒有切分的更小

可是有的使用者樣例本身就超過100點
甚至傷筋動骨1000點都不夠用
可那還是13點怎辦?

政治能力的培養永遠不嫌晚
能閃則閃
拆東牆補西牆
比如說原本的一點的任務報13點
讓接到此故事的工程師能少賠一點

閃不掉的,又不補其它好康的給你時
工程師就得用下班時間來補囉
不然KPI很難看

人家13點一小時做完
你要做那麼多天
你知道人事部門只看報表做事嗎?

原本是發現問題的好機制
結果變成劣幣驅逐良幣的好機制

為什麼呢?因為問題會找人
難解的問題會自然流向強力工程師那
PM只管解目前難題,他不會管公平性問題

久而久之,爽的人會很爽
不爽的人會更不爽

所以我現在一聽到有某某公司在run Scrum
隨便觀察幾個關鍵地方就知道會不會成功了
根本無需深入團隊

體制直接決定成敗
因為你只是口頭上說Scrum
和某人喊全民脫貧不是一樣的東西嗎?

又回到老問題
張嘴就來 口說就有

從今日到永永遠遠
唯有上帝耶和華
昔在今在永在神

所以謙卑才是能不能成功的要素

gaussian1998 發表在 痞客邦 留言(1) 人氣()

之前忘記帳號密碼

完全無法登入部落格

今天在某個記事本神奇找到密碼

 

最近迷上AI繪圖,所以做了一個網站

https://stable.signage-cloud.org

AI 線上魔法辭典

用來幫助自己紀錄一些常用提詞

不用翻著excel表在那邊無從下手

 

這個網站本來是用來預備將阿瓦隆練習台移殖到dotnet core的試驗程式碼

做著做著就做歪了,專案名稱是 Avalon, 結果內容卻變成一個AI線上繪圖的排程器

懶得改專案名

 

我還有一個放紅白機攻略本的網站

http://game.signage-cloud.org

之前用ruby on rails寫的

雖然已成功改成dotnet core,但架構和原來ROR是一樣的

擴充性很差, 等我重構完這個網站

我就會回去把之前那個阿瓦隆練習台搬到 dotnet core 上

http://avalon.signage-cloud.org

順便裡一下架構, 讓它可以快速擴充成其他種類的桌游遊戲

 

下一個桌游遊戲會以可以少數幾個人就可以成團的為主

阿瓦隆不要說是湊10個人了, 5個人都很困難

 

我小朋友很喜歡玩內線交易

下一個寫內線交易不知道好不好 ~ 哈

 

我把架構理出來後,可能會用這些網站當成學習樣本

教大家自己建構自己的web站台

只是不知道這種教學影片有多少人看呢?

試了一下 ~ 好像不大妙阿

不知道大家是怎麼想的?

 

 

 

 

 

 

 

文章標籤

gaussian1998 發表在 痞客邦 留言(10) 人氣()

class Singleton

{

   public:

       static Singleton& getInstance();

};

 

Singleton& Singleton::getInstance()

{

   static Singleton singleton;

   return singleton;

}

 

特點:

  第一次呼叫getInstance()會初始化物件,第二次以後會沿用同一個物件

  多執行緒的情況下請自行加鎖

 

gaussian1998 發表在 痞客邦 留言(0) 人氣()

class A
{
    private:
        int *const array;

    public:
        A()
        {
            array = new int[10];
        }

        ~A()
        {
            delete [] array;
        }
};

int main()
{
    A a1;
    A a2 = a1;
}

問:

這個類別無疑挖了一個深坑

請問如何保護使用者在沒看到原始碼情況下

也能寫出正確的程式碼

 

答:

自定義拷貝建構式和設定運算子為私有並且不實作它

class A
{
    private:
        int *array;
    public:
        A()
        {
            array = new int[10];
        }

        ~A()
        {
            delete [] array;
        }

    private:
        A(const A &other);
        A& operator=(const A &other);

};
 

 

如果各位運氣不錯,手上編議器支援C++11

 

class A
{
    private:
        int *array;
    public:
        A()
        {
            array = new int[10];
        }

        ~A()
        {
            delete [] array;
        }


        A(const A &other) = delete;
        A& operator=(const A &other) = delete;

};

 

編譯器會給你一個大大的警示,說拷貝建構式和設定運算子被刪除

gaussian1998 發表在 痞客邦 留言(0) 人氣()

有些系統偏好堆疊式架構

使用new運算子是邪惡的

 

問: 如何在語言層面避免工程師使用new運算子

答: 自定義一個私有的operator new運算子,然後不實作它

#include <cstddef>

class Man
{

private:
    static void* operator new(const size_t size); // 只定義不實作

};

int main()
{
    new Man(); // 編譯錯誤

    return 0;
}

gaussian1998 發表在 痞客邦 留言(0) 人氣()

// Man.hpp
class Man
{
private:
    class Impl;
    Impl *const m;

public:
    Man();
    ~Man();

public:
    void setAge(const int age);
};


// Man.cpp

#include <Man.hpp>

struct Man::Impl
{
    Impl()
    {
        age  = 20;
    }

    int age;
};

Man::Man()
:m( new Impl() )
{}

Man::~Man()
{
    delete m;
}

void Man::setAge(const int age)
{
    m->age = age;
}

 

問: 有什麼好處?

答:

變更類別的成員變數時,只需要重新編譯Man.cpp檔並且連結即可

所有相依於Man.hpp檔的模組都無須重新編譯

 

gaussian1998 發表在 痞客邦 留言(0) 人氣()

class Integer
{
public
    void get() const;
    void set(int value);
};

 

問: 類別成員函式後面 const 是什麼意思?

答: 

Integer a;

a.get(); // 可

a.set(10); // 可

 

const Integer b;

b.get(); // 可 

b.set(10); // 不可,編譯錯誤

 

結論:

沒加const的成員函式在物件被宣告const時會被編譯器擋下來

加了const的成員函式在任何時候都可被使用

這段語法可以幫助程式猿區分可變和不可變函式

C#和Java沒對應的語法 ( python, ruby, kotlin , javascript 也沒有  )

轉職的工程師請自己保重

gaussian1998 發表在 痞客邦 留言(0) 人氣()

class INetTool
{
public:
    virtual ~INetTool(){};

    virtual string onHttpGet(const char *const url)=0;
    virtual string onHttpPost(const char *const url, const char *const request)=0;
    virtual bool onDownload(const char *const url, const char *const savePath)=0

};

 

class HttpToolA : public INetTool

{ int value; }

class HttpToolB : public INetTool

{ float value[10]; }

class HttpToolC : public INetTool

{ double value[100]; }

 

 

問: 為何上述虛擬解構式是一定要的?

答: 因為你會這樣做

INetTool *const a = new HttpToolA();

INetTool *const b = new HttpToolB();

INetTool *const c = new HttpToolC();

release(a);

release(b);

release(c);

 

// 哪個子類別傳進來?

// 你問我我問虛擬函式表

void release(INetTool *const tool)

{

   delete tool;

}

 

 

虛擬解構式會產生虛擬函式表

裡面含有足夠多的執行時期資訊

可以讓delete運算子安全釋放資源

 

gaussian1998 發表在 痞客邦 留言(0) 人氣()

class A{

public:
    A()
    {
        std::cout << "A" << std::endl;        
    }

    ~A()
    {
        std::cout << "~A" << std::endl;
    }

};

class B{

public:
    B()
    {
        std::cout << "B" << std::endl;        
    }

    ~B()
    {
        std::cout << "~B" << std::endl;
    }

};

int main()
{
    A a;
    B b;
}

問: 上述輸出為何?

答:
A
B
~B
~A


問: 應用場景
答: 機算機資源控管,稱為RAII範式

 

 

 

 

 

 

 

 

// 
// 沒C++ 可以寫 轉戰 C# 的工程師看這
//
class A : IDisposable
{
    public A()
    {
        Console.WriteLine("A()");
    }

    void Dispose()
    {
        Console.WriteLine("~A()");
    }
}

class B : IDisposable
{
    public B()
    {
        Console.WriteLine("B()");
    }

    void Dispose()
    {

        Console.WriteLine("~B()");

    }
}

static void Main(string[] args)
{
    using (var a = new A { })
    {
        using (var b = new B { })
        {
        }
    }
}

 

// 沒C++ 可以寫 轉戰 Java 的工程師看這, Java 8以上可用
// 但是很多專案還是用Java 6, Java 7 包含 Android
public class A implements AutoCloseable 
{
    public A()
    {
        System.out.println("A()");
    }


    @Override
    public void close() throws Exception 
    {
        System.out.println("~A()");
    }
}

public class B implements AutoCloseable 
{
    public B()
    {
        System.out.println("B()");
    }


    @Override
    public void close() throws Exception 
    {
        System.out.println("~B()");
    }
}

public static void main(String[] args)
{
    try (A a = new A() ) 
    {
        try (B b = new B() ) 
        {
        }
    }
}

gaussian1998 發表在 痞客邦 留言(0) 人氣()

template<int n>
struct Sum{

    enum { value = n + Fibonacci<n-1>::value };
};

template<>
struct Sum<1>{

    enum { value = 1 };
};

const int A = Sum<5>::value;

問: 請問變數A的值是多少?

答: 5 + 4 + 3 + 2 + 1 = 15

 

問: A 何時被決定?

答: 編譯時期

 

gaussian1998 發表在 痞客邦 留言(0) 人氣()

1 2