搜尋此網誌

2013/11/12

柔性 vs 硬式管理

我認為柔性與硬式管理的效果在理論與實務上都是對的,二者並不衝,這本就是管理上的藝術面
管理學自己都承認:「天底下沒有放諸四海皆準的管理準則」與「管理既是科學也是藝術」。

以專案管理為例好了,大家常聚集在工作分解、資源分配、排時程等事項,這都屬於專案管理的科學面
菜鳥 PM 也常誤以為這些事做好之後專案就一定成功,因此所有的專案管理書籍與講師最後一定會提醒大家:

科學面的技術與工具只是專案成功的必要條件,而不是充分條件
專案到頭來還是人去執行的,所以最後的成敗還是在人員管理

所以要提高成功機率就必須技術/工具與人員管理並重。

以我自己的經驗來說,柔性管理:
  • 重點主要是讓經理人(Manager)變成領導者(Leader)。
  • 第一步要分清楚經理人與領導者的區別。
    • 經理人只靠職權去驅動人員(利用大家懼怕職權的心理)
    • 但是領導者靠其專業、提供方向、以身作則...等來引導人員。(完全不靠職權)
    • 這個時代只靠職權是什麼都做不了的。(上有政策,下有對策)
  • 在工作以外的部分可以放入更多人性,例如人員的職涯規劃與訓練,在金錢上儘量在一定範圍內多滿足人員,...
  • 簡言之就是收買人心的方法。
硬式管理:
  • 通常指的是堅持工作原則與規範,目的是吸引優秀的人同時快速淘汰無法勝任的人
  • 提供成員必要的訓練,預先掃除其執行障礙,然後要求成員必須遵守流程與準則。
融合上述兩個方式的期望效果是:

  • 找出願意學習與進步的人並收買其人心,同時也過濾出學習態度不佳也不努力的庸才並加以淘汰。
  • 最終目的就是留住人才快速淘汰庸才
庸才的影響力遠比想像的還大因為
  • 這樣的人會做出不良示範,讓真正的人才心中不服,接著必然無法貫徹團隊目標
  • 如果經理人放任此行為將造成其他人心中誤以為這是經理人的意向,這損失就大了!
  • 接下來經理人就會被認為無能,同時也會錯誤暗示大家這裡有特權是個不公平的地方。

真搞成這樣的話,即使團隊的人再強也將無法有任何作為了(團隊癱瘓)。

最近看到 Google 的人員管理才發現原來在這個人人稱羨的工作環境之中,
新進人員竟然只有一年可以證明自己,若證明不了的話一年後就得
因為 Google 只願意給人才享用這些被人羨慕的環境與福利,對於庸才 Google 連沾都不讓他沾。
(我的猜測:Google 應該只是把庸才的薪資與福利分配給人才而已,總成本並未增加多少)

Google 這樣算是軟或硬呢?

專案計畫 vs 工作計畫

專案計畫 vs 工作計畫

很多人誤會了一件事,誤以為好像只有專案經理才需要做計畫。
其實專案管理是要求專案經理去引導所有的專案成員去共同規劃

專案計畫與個人工作計畫是兩回事個人工作計畫不會自動支援專案計畫尤其在跨部門時更明顯。
如果沒有專案計畫的話,專案管理為保險起見會把所有項目都說成第一優先,但卻沒有什麼根據。

但是一個面對多個專案的人員來說:可能把所有項目都擺在第一優先
所以最後只能以職位與權力來排優先順序,所以高層人員通常感覺不到有任何影響(與事實不符的感覺)
但是誰都知道這遲早會出問題的。(因為當所有事項都是第一優先就等於沒有任何優先,除非你的權力夠大)

把若干人組成一個小組也是很不錯的想法,因為這可以在小範圍下培養出 leader
因為大家都知道要直接培養出一個專案理是非常費時、費成本,也無人能保證一定成功。

所以幾乎所有軟體公司在 PM 之下都會再分出多位 module leader 的原因之一也是如此。
不談空降的 PM,內昇儲備 PM 通常就是由這些 module leader 挑選出來做進一步培訓的。

通訊的設計模式: Channel-Queue

通訊的設計模式: Channel-Queue



2013/08/20

一個簡單的 Delphi O/R Mapping 工具

一個簡單的 Delphi O/R Mapping 工具。
這裡好像無法上傳檔案,需要者可與我聯絡:

  albertdongtw@gmail.com

或由此下載:

Download

Entity Builder主要的功能在於產生Delphi類別來對映(mapping)既有的資料表。基本上,資料表的欄位會對映到Delphi類別的屬性(property)。但是手動做這些工作是非常辛苦的,所以我們可以使用這個工具程式來建立基本的類別骨架。
執行程式後的啟始畫面。


按下「建立ADO連線」按鈕設定ADO連線。

接著如同使用TADOConnection元件般設定ConnectionString



此時會顯示資料庫與資料表(不含系統資料表)清單。

由資料表清單選擇一個資料表。


按「預覽」按鈕即可顯示產生的程式碼。可按滑鼠右鍵儲存到檔案或是複製到剪貼簿。




  
產生出來的完整程式碼如下:
{-------------------------------------------------------------------------------
This file is generated by EntityBuilder v1.2
provided by Albert Dong, albertdongtw@gmail.com

The Template Engine is from:
    http://sourceforge.net/projects/delphi-templeng/
--------------------------------------------------------------------------------

Class: User
Table: user
Author: XXX
Date: 2013/8/20 下午 07:06:39
Description:
-------------------------------------------------------------------------------}

unit uUser;

interface

uses
  Windows, Messages, SysUtils, Variants, Contnrs, Classes, DB, uEntity;

const
  TBL_User = 'user';

type
  {**
   * Class description.
   *
   * @author XXX, 2013/08/20 19:06:39. Created.
   *}
  TUser = class(TEntity)
  private
    // ------ Fields ------
    FNo: string;
    FName: string;
    FNameEng: string;
    FEmail: string;
    FRecvCalNotify: integer;
    FRecvCalOverdue: integer;
    FIsAdmin: integer;

  protected
    // ------ Property Accessors ------
    function GetNo: string;
    procedure SetNo(value: string);

    function GetName: string;
    procedure SetName(value: string);

    function GetNameEng: string;
    procedure SetNameEng(value: string);

    function GetEmail: string;
    procedure SetEmail(value: string);

    function GetRecvCalNotify: integer;
    procedure SetRecvCalNotify(value: integer);

    function GetRecvCalOverdue: integer;
    procedure SetRecvCalOverdue(value: integer);

    function GetIsAdmin: integer;
    procedure SetIsAdmin(value: integer);


    procedure FillData(DataSet: TDataSet); override;

  public
    // ------ Utility Class Methods ------
    class function ListAll: TList;
    class procedure DeleteAll;

    constructor Create; override;
    destructor Destroy; override;

    function ToString: string; override;

    procedure Reload;
    procedure Insert;
    procedure Update;
    procedure Delete;

  published
    // ------ Properties ------
    property No: string read GetNo write SetNo;
    property Name: string read GetName write SetName;
    property NameEng: string read GetNameEng write SetNameEng;
    property Email: string read GetEmail write SetEmail;
    property RecvCalNotify: integer read GetRecvCalNotify write SetRecvCalNotify;
    property RecvCalOverdue: integer read GetRecvCalOverdue write SetRecvCalOverdue;
    property IsAdmin: integer read GetIsAdmin write SetIsAdmin;
  end;

implementation

uses
  uToString;

{ TUser }

class function TUser.ListAll: TList;
var
  stmt: string;
begin
  stmt := 'SELECT * FROM ' + TBL_User;
  result := TEntity.ExecQueryForList(stmt, TUser);
end;

class procedure TUser.DeleteAll;
begin
  ExecUpdate('DELETE FROM ' + TBL_User);
end;

constructor TUser.Create;
begin
  inherited Create;
  // TODO: Constructor...
end;

destructor TUser.Destroy;
begin
  // TODO: Destructor...
  inherited Destroy;
end;

(**
 * Fill object properties with the specified dataset.
 * Every subclass of TEntity inherits AsXXX() methods.
 *
 * @param DataSet the specified dataset.
 *)
procedure TUser.FillData(DataSet: TDataSet);
begin
  if DataSet = nil then
    raise Exception.Create('Nil DataSet!');

  if DataSet.IsEmpty or DataSet.Eof then
    Exit;

    FNo := AsString(DataSet, 'no');
    FName := AsString(DataSet, 'name');
    FNameEng := AsString(DataSet, 'name_eng');
    FEmail := AsString(DataSet, 'email');
    FRecvCalNotify := AsInteger(DataSet, 'recv_cal_notify');
    FRecvCalOverdue := AsInteger(DataSet, 'recv_cal_overdue');
    FIsAdmin := AsInteger(DataSet, 'is_admin');
end;

procedure TUser.Reload;
var
  stmt: string;
begin
  stmt := 'SELECT * FROM ' + TBL_User
        + ' WHERE 1 = 1 '
        + '   AND no = ' + QuotedStr(No)
    ;

  TEntity.Load(stmt, self);
end;

procedure TUser.Insert;
var
  stmt: string;
begin
  stmt := 'INSERT INTO ' + TBL_User + ' ('

        + 'no'

        + ', name'

        + ', name_eng'

        + ', email'

        + ', recv_cal_notify'

        + ', recv_cal_overdue'

        + ', is_admin'

        + ') VALUES ('

        + QuotedStr(No)

        + ', ' + QuotedStr(Name)

        + ', ' + QuotedStr(NameEng)

        + ', ' + QuotedStr(Email)

        + ', ' + IntToStr(RecvCalNotify)

        + ', ' + IntToStr(RecvCalOverdue)

        + ', ' + IntToStr(IsAdmin)
        + ') '
    ;

  ExecUpdate(stmt);
end;

procedure TUser.Update;
var
  stmt: string;
begin
  stmt := 'UPDATE ' + TBL_User + ' SET '

        + 'no = ' + QuotedStr(No)

        + ', name = ' + QuotedStr(Name)

        + ', name_eng = ' + QuotedStr(NameEng)

        + ', email = ' + QuotedStr(Email)

        + ', recv_cal_notify = ' + IntToStr(RecvCalNotify)

        + ', recv_cal_overdue = ' + IntToStr(RecvCalOverdue)

        + ', is_admin = ' + IntToStr(IsAdmin)

        + ' WHERE 1 = 1 '
        + '   AND no = ' + QuotedStr(No)
    ;

  ExecUpdate(stmt);
end;

procedure TUser.Delete;
var
  stmt: string;
begin
  stmt := 'DELETE FROM ' + TBL_User
      + ' WHERE 1 = 1 '
      + '   AND no = ' + QuotedStr(No)
    ;
  ExecUpdate(stmt);
end;

function TUser.ToString: string;
begin
  TToStringBuilder.toString(self);
end;

function TUser.GetNo: string;
begin
  result := FNo;
end;

procedure TUser.SetNo(value: string);
begin
  if FNo <> value then begin
    FNo := value;
  end;
end;

function TUser.GetName: string;
begin
  result := FName;
end;

procedure TUser.SetName(value: string);
begin
  if FName <> value then begin
    FName := value;
  end;
end;

function TUser.GetNameEng: string;
begin
  result := FNameEng;
end;

procedure TUser.SetNameEng(value: string);
begin
  if FNameEng <> value then begin
    FNameEng := value;
  end;
end;

function TUser.GetEmail: string;
begin
  result := FEmail;
end;

procedure TUser.SetEmail(value: string);
begin
  if FEmail <> value then begin
    FEmail := value;
  end;
end;

function TUser.GetRecvCalNotify: integer;
begin
  result := FRecvCalNotify;
end;

procedure TUser.SetRecvCalNotify(value: integer);
begin
  if FRecvCalNotify <> value then begin
    FRecvCalNotify := value;
  end;
end;

function TUser.GetRecvCalOverdue: integer;
begin
  result := FRecvCalOverdue;
end;

procedure TUser.SetRecvCalOverdue(value: integer);
begin
  if FRecvCalOverdue <> value then begin
    FRecvCalOverdue := value;
  end;
end;

function TUser.GetIsAdmin: integer;
begin
  result := FIsAdmin;
end;

procedure TUser.SetIsAdmin(value: integer);
begin
  if FIsAdmin <> value then begin
    FIsAdmin := value;
  end;
end;


initialization
  // Register this entity class for dynamic loading.
  RegisterClass(TUser);

finalization
  UnRegisterClass(TUser);


end.