2018年4月21日 星期六

A pattern for state machine II - SM framework


我將A pattern for state machine改寫成framework形式,使用者需要先使用sm_alloc()分配一個struct sm,再使用sm_fp_reg()將每個state的callback function掛上,最後有event要執行時,只要呼叫sm_run(sm, new_event)即可。
state的callback function的撰寫邏輯,大致與之前一樣,return下一個state,進入下一個state要做的動作,我都用do_state_x()包起來,而do_state_x()會return 該state。

sm.h

#ifndef SM_H
#define SM_H

struct sm {
    int cur_state;
    int prv_event;
    void *v;
};

/**
 * state function
 * @return next state
 */
typedef int (*sm_st_fp)(struct sm *sm, int new_event);
struct sm *sm_alloc(int num_of_state);
int sm_run(struct sm *s, int new_event);
int sm_fp_reg(struct sm *s, int state, sm_st_fp fp);

#endif


sm.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sm.h"

struct _sm {
    struct sm s;
    int num_of_st;
    sm_st_fp fp[0];
};

struct sm *sm_alloc(int num_of_state)
{
    struct _sm *_s;
    int sz;

    sz = sizeof(struct _sm) + sizeof(sm_st_fp) * num_of_state;
    _s = (struct _sm*) malloc(sz);
    if (!_s) {
        return NULL;
    }
    memset(_s, 0, sz);
    _s->num_of_st = num_of_state;
    return (struct sm*)_s;
}

int sm_run(struct sm *s, int new_event)
{
    struct _sm *_s = (struct _sm*) s;
    if (s->cur_state > _s->num_of_st) {
        printf("out of st\n");
        return -1;
    }

    if (!_s->fp[s->cur_state]) {
        printf("null fp\n");
        return -1;
    }

    s->cur_state = _s->fp[s->cur_state](s, new_event);
    s->prv_event = new_event;
    return 0;
}

int sm_fp_reg(struct sm *s, int state, sm_st_fp fp)
{
    struct _sm *_s = (struct _sm*) s;
    if (state > _s->num_of_st) {
        printf("out of st\n");
        return -1;
    }

    _s->fp[state] = fp;
    return 0;
}


main.c

因為是framework,所以,我把state/event都拉出來,
因此每個State Machine都應該定義自己的event與state。
enum state {
    STATE_1,
    STATE_2,
    STATE_3,
    STATE_4,
};

enum event {
    E1 = 1,
    E2,
    E3,
    E4,
};

int main(int argc, char *argv[])
{
    struct sm *s;
    char ch;
    s = sm_alloc(3);
    if (!s) {
        return -1;
    }
    sm_fp_reg(s, STATE_1, in_state_1);
    sm_fp_reg(s, STATE_2, in_state_2);
    sm_fp_reg(s, STATE_3, in_state_3);
    sm_fp_reg(s, STATE_4, in_state_4);
    while (1) {
        while (((ch = getc(stdin)) == '\n') || (ch < '0') || (ch > '4'));
        sm_run(s, ch - '0');
    }

    return 0;
}


refine callback function

因為是framework,所以,callback function的定義要改成return int。
int do_s1(void)
{
    printf("%s(#%d)\n", __FUNCTION__, __LINE__);
    return STATE_1;
}

int do_s2(void)
{
    printf("%s(#%d)\n", __FUNCTION__, __LINE__);
    return STATE_2;
}

int do_s3(void)
{
    printf("%s(#%d)\n", __FUNCTION__, __LINE__);
    return STATE_3;
}

int do_s4(void)
{
    printf("%s(#%d)\n", __FUNCTION__, __LINE__);
    return STATE_4;
}


int in_state_1(struct sm *s, int new_event)
{
    printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event);
    switch (new_event) {
        case E1:
            printf("change to S2\n");
            return do_s2();
        case E2:
            printf("change to S3\n");
            return do_s3();
        default:
            printf("keep the same STATE && do nothing\n");
            return STATE_1;
    }
}

int in_state_2(struct sm *s, int new_event)
{
    printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event);
    switch (new_event) {
        case E3:
            printf("change to S3\n");
            return do_s3();
        default:
            printf("keep the same STATE && do s2 again\n");
            return do_s2();     // do s2 again
    }
}

int in_state_3(struct sm *s, int new_event)
{
    printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event);
    switch (new_event) {
        case E2:
            printf("change to S4\n");
            return do_s4();
        default:
            printf("keep the same STATE && do nothing\n");
            return STATE_3;
    }
}

int in_state_4(struct sm *s, int new_event)
{
    printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event);
    switch (new_event) {
        case E1:
            printf("change to S2\n");
            return do_s2();
        case E3:
            printf("change to S1\n");
            return do_s1();
        default:
            printf("keep the same STATE && do again\n");
            return do_s4();
    }
}



2018年4月15日 星期日

赫茲伯格的雙因素激勵理論 - 筆記


雙因素理論(Two Factor Theory)又叫激勵保健理論(Motivator-Hygiene Theory),是美國的行為科學家弗雷德里克·赫茨伯格(Fredrick Herzberg)提出來的。
赫茨伯格著手研究哪些事情使人們在工作中快樂和滿足,哪些事情造成不愉快和不滿足。結果他發現,使員工感到滿意的都是屬於工作本身或工作內容方面的;使員工感到不滿的,都是屬於工作環境或工作關係方面的。他把前者叫做激勵因素,後者叫做保健因素。
那些能帶來積極態度、滿意和激勵作用的因素就叫做“激勵因素”,這是那些能滿足個人自我實現需要的因素,包括:具挑戰性的工作、自主權、嘉獎和升遷。

根據赫茨伯格的理論,在調動員工積極性方面,可以分別採用以下兩種基本做法:
(一)直接滿足
直接滿足,又稱為工作任務以內的滿足。它是一個人通過工作所獲得的滿足,這種滿足是通過工作本身和工作過程中人與人的關係得到的。它能使員工學習到新的知識和技能,產生興趣和熱情,使員工具有光榮感、責任心和成就感。
(二)間接滿足
間接滿足,又稱為工作任務以外的滿足。這種滿足不是從工作本身獲得的,而是在工作以後獲得的。例如晉升、授銜、嘉獎或物質報酬和福利等,就都是在工作之後獲得的。在使用這種激勵因素時,必須與個人的工作績效掛鉤。否則一味的“吃大鍋飯”,久而久之,獎金就會變成保健因素,再多也起不了激勵作用。




2018年4月7日 星期六

note for "The Art of Readable Code" - CH9 Variables and Readability


減少不必要的變數可以增加閱讀性, 比如
root_message.last_view_time = datetime.datetime.now()
會比下面code更容易理解
now = datetime.datetime.now()
root_message.last_view_time = now

下面還有幾個需要優化的的例子, 可以好好思考如何改善.
boolean done = false;
while (/* condition */ && !done) {
    ...
    if (...) {
        done = true;
        continue;
    }
}
與
var remove_one = function (array, value_to_remove) {
    var index_to_remove = null;
    for (var i = 0; i < array.length; i += 1) {
        if (array[i] === value_to_remove) {
            index_to_remove = i;
            break;
        }
    }
    if (index_to_remove !== null) {
        array.splice(index_to_remove, 1); 
    }
};


programmer都知道要盡量限縮變數的範圍, 因為可視範圍小, 要記住的變數數量也會減少, 也且可以避免global/local variable用錯的窘境.
submitted = false; // Note: global variable
var submit_form = function (form_name) {
    if (submitted) {
        return;  // don't double-submit the form
    }
    ...
    submitted = true;
};
可以被修改成
var submit_form = (function () {
    var submitted = false; // Note: can only be accessed by the function below
    return function (form_name) {
        if (submitted) {
            return;  // don't double-submit the form
        }
        ...
        submitted = true; 
    };
}());


    參考資料:
  1. The Art of Readable Code




熱門文章