分類彙整:programming

Composer進階原理:PHP命名空間與PSR-0

上次的Composer設計原理與基本用法說明了PHP套件管理的歷史與社群提出的解決之道,本篇文章接著談類別管理的進階議題。

當類別名稱一樣…

當專案大了起來,有時候會有類別名稱重複的問題。
假設今天要撰寫一個論壇模組,提供討論區與留言板功能。
你一定很想將討論區的文章與留言板的文章都命名類別為Article:

// BoardArticle.php

// ForumArticle.php

當然了,這麼做會得到一個結果:

Fatal error: Cannot redeclare class Article

這種問題有一個簡單的解決辦法,就是加上前綴字。
類別分別命名為ForumArticle與BoardArticle就可以了。

Q1: 等一下!這個解法好陽春!我看到至少4個問題:
1. 類別名稱容易變得冗長。
2. 有些類別一開始你以為不會跟人重複,結果之後真的重複了。難道永遠替類別加前綴字?
3. 類別名稱寫Article俐落多了!文章就是概念上的文章,不要逼我告訴你是討論區還是留言板!如果專案用到兩種留言板模組,分別由以前的兩個前輩寫好,難道還要逼我把作者名稱寫進去?

class TonyBoardArticle{
  //...
}
class JackBoardArticle{
  //...
}


4. 如果我在打造框架(framework)呢?幾乎會把所有常見名詞用過一次(像是Request、Loader、Response、Controller、Model等類別)!難道前面全部前綴?
看看Codeigniter的原始碼,全部用CI_當作前綴。超醜的。

命名空間(namespace)登場

於是PHP從5.3版之後支援了命名空間(namespace)。
所以可以用Article替類別定義了:

// BoardArticle.php

// ForumArticle.php

使用類別時只要加上命名空間即可:

//index.php

如果當前的php檔只用到其中一個Article類別,可以指定當前的php檔只用哪個命名空間+類別的組合:


如此一來,當php找不到Article類別時,便會去使用use關鍵字宣告的組合。
當然了,就算用use指定過,原本的宣告方式還是可以用的。(如最下方兩行所示)

當東西多了起來...

OK,可以繼續完成我們的論壇模組了!
討論區跟留言板有各自的文章,再來還需要「推文」:



使用剛剛學到的命名空間去載入他們:


果然是漂亮的各種命名阿!


Q2: include有好多行!上次的Composer設計原理與基本用法提到了Composer可以解決這種問題,當引入命名空間之後,Composer也能發揮作用嗎?

是的。

Composer登場

跟上次初學Composer一樣,建立一個composer.json檔:

{
    "autoload": {
        "files": [
            "ForumArticle.php",
            "ForumComment.php",
            "BoardArticle.php",
            "BoardComment.php"
        ]
    }
}

注意,上次我們用"classmap"指定資料夾、把資料夾內檔案全掃一次,這次我們用"files"分別設定各個檔案。

再來,在terminal輸入

composer install

執行完畢之後,跟上次一樣,只要載入一個檔案:


就可以使用各個類別囉!


Q3: 等一下!看起來跟沒有命名空間的時候差不多啊!一樣是把php檔自動require進去而已?

對啊,你最上面的原始寫法,也只是手動載入好幾個檔案,在載入的時候本來就沒有特別之處:


載入php檔就只是載入,跟命名空間是兩回事。


Q4: 還是不太對啊!上次我用classmap一次把好幾個資料夾內容掃過,這次我用files分別指定每個檔案幹嘛?Composer不是厲害在能指定資料夾去自動掃過?

......你說的沒錯。
開個my_lib資料夾,把4個php檔都丟進去吧。composer.json這樣寫就好了:

{
    "autoload": {
        "classmap": [
            "my_lib"
        ]
    }
}

再來,在terminal輸入

composer install

這樣就搞定了!
其實我只是想示範,除了用classmap設定資料夾之外,也可以用files直接指定檔案。

Q5: OK,原諒你。不過,我必須說,我今天什麼都沒學到。最後還是在composer.json寫classmap而已,跟上次一模一樣。

是的...我剛說了,載入php檔就只是載入,跟命名空間是兩回事。
我今天介紹的namespace功能是PHP本身提供的。而Composer只是協助你載入的工具、當然不可能改變程式語言本身。
Composer只是幫助你少打那一串require而已。


Q6: ㄟ等等...有個地方我覺得很醜。我們現在的my_lib資料夾裏面有4個檔案,檔名很醜:

"ForumArticle.php"
"ForumComment.php"
"BoardArticle.php"
"BoardComment.php"


類別名稱本身都是俐落的Article跟Comment了,檔案名稱還是有前綴字。但也不可能有兩個Article.php、兩個Comment.php。你有沒有辦法解決這個美感問題?

這個問題簡單,把那個my_lib資料夾刪掉,開一個Forum資料夾、一個Board資料夾。本來的ForumArticle.php改成Article.php丟進Forum資料夾、本來的BoardArticle.php改成Article.php丟進Board資料夾。composer.json改寫成這樣:

{
    "autoload": {
        "classmap": [
            "Board",
            "Forum"
        ]
    }
}

再來,在terminal輸入

composer install

這招不錯吧!檔案名稱就是類別名稱,乾淨俐落!
而且資料夾的名字本身就是namespace的名稱!
以後都這樣做啦!一用到命名空間就開個同名資料夾把檔案丟進去!

Q7: 這招我覺得還好耶...。本來檔案都放在my_lib,我在composer.json只要填my_lib一行就好,現在變成要填兩行。要是我這個論壇模組有一大堆類別、用了一大堆命名空間呢?那我classmap底下不就要填入好幾行?那我寧可全部丟進my_lib,只填my_lib一行!

唔,這樣說也是有道理。那重新建立my_lib資料夾,把Board跟Forum資料夾丟進my_lib資料夾。composer.json改回這樣寫:

{
    "autoload": {
        "classmap": [
            "my_lib"
        ]
    }
}

再來,在terminal輸入

composer install

classmap不只是告訴Composer去載入哪幾個資料夾內的檔案,還會把資料夾內的資料夾也全部掃過一次。
怎麼樣,Composer夠神吧。


Q8: 原來classmap底下會遞迴掃描下去...。我決定了,我的Forum跟Board都是在提供線上討論功能,我決定替我這個模組命名為Discussion。我要在my_lib底下開Discussion資料夾,然後把原本的Forum跟Board資料夾都丟進去。你覺得這個想法如何?

還不錯。一個Discussion資料夾就是你的整個Discussion模組。
提供了討論區、留言板功能的Discussion模組,我喜歡。


Q9: 好像忘了什麼...。啊,剛剛說命名空間跟檔案結構符合會最漂亮。那我要把那4個檔案的namespace改成這樣:



剛剛說了,載入檔案就只是載入檔案,跟命名空間無關。
現在檔案結構沒變,所以我應該不用重新輸入composer install。
讓我試試...。
靠!怎麼噴error了!你騙我?

Fatal error: Class 'Discussion\Forum\Comment' not found 

呃...,我前面的說法確實有點誤導。
PHP自動載入的基本函式長這樣:

void __autoload ( string $class )

如你所見,PHP至少需要Composer提供資訊指出$class該去哪個檔案找。
namespace改變之後,PHP會找不到對應的$class在哪。
所以還是輸入一下composer install吧!Composer會把需要的資訊整理好的。


Q10: OKOK,我知道了,我駕馭這一切了。我覺得這個Dicsussion模組真的超屌的,不但命名空間漂亮,連檔案結構都漂亮。我要把這個Discussion資料夾整個丟給我朋友,他們公司最近需要論壇模組。
讓我打電話給他...。
「什麼?你們已經做好半個論壇模組了?你只需要我模組的其中幾個功能?你們的模組也是放在Discussion資料夾?」
糟糕,資料夾名稱重複了!所以我的模組拿給別人還是有不相容的可能,怎麼辦?

沒有錯..還記得你Q1提到的第3個狀況嗎?確實有把作者名稱加進去的必要!
別怕,我教你。你開一個Tony資料夾,把整個Discussion資料夾丟進去。
接著所有檔案namespace改成像這樣:


要用的時候就這樣喔:


是變得有點長啦。
但這下搞定了吧!作者名稱再撞到的話,就改個獨特的名稱就是了!

終於。讓我們談談PSR-0

你一定常聽到PSR-0對吧!
PSR-0是PHP跨框架相容性統一標準組織訂出來的自動載入慣例。

來談談PSR-0幾個最重要的要求吧!

* 命名空間加上類別名稱一定要長這樣:

\\(\)*

* 前面一定要是作者名稱
* 中間可以有任意層次的命名空間、最後是類別名稱。
* 中間任意層次的命名空間直接對應到檔案結構。

發現了嗎?在剛剛Q1~Q10的過程中,其實你已經把PSR-0學完了,連設計原理都一起搞懂了。

懂這些之後,你也可以做好自己的模組、發佈到Packagist給全世界透過composer下載、使用了!

最後,如果遵守psr-0的話,composer.json可以這樣寫:

{
    "autoload": {
        "psr-0": {
            "Tony\\Discussion\\": "my_lib/"
        }        
    }
}

注意,雙引號、兩次反斜線並沒有特別意思,只是json規定的格式。

跟classmap一樣都可以完成任務。兩者其實是有差別的...,我們下次再談。

結語

Composer工具以及PHP-FIG組織的出現,讓一直以來散落各地的PHP社群開始有集中的趨勢。
換句話說,各社群終於能共享彼此的library了。
然而,如你所見,psr-0不但導致檔案結構容易變得深層,還要求檔案結構必須配合程式碼,這也招致了不少批評
除此之外,composer autoload內的classmap跟psr-0到底如何分工?效能差異又為何?這些問題也都還在爭論與驗證當中。

不過,PSR-0在各框架已被廣泛支援,因此建議你還是需要有所瞭解。

最後...

現在已經出現psr-0的替代方案,稱為psr-4

PSR-0從2014-10-21開始被註明為不建議使用。
至於PSR-4..我們下次再談。

Laravel:20分鐘完成Facebook登入功能

要實作Facebook的OAuth 2.0登入流程,最基本的方法是先瞭解OAuth 2.0協定內容,接著到Facebook官網下載程式語言的SDK、註冊應用程式,然後照著官方文件實作。

但如果使用Laravel的話,直接使用社群提供的package就可以囉。本文介紹artdarek/oauth-4-laravel的使用。

首先要下載這個套件。在指令列輸入:

composer require 'artdarek/oauth-4-laravel:dev-master'

自動下載完畢之後,在’app/config/app.php’內加入兩個value:

'providers' => array(
    // ...

    'Artdarek\OAuth\OAuthServiceProvider'
)

'aliases' => array(
    // ...

    'OAuth' => 'Artdarek\OAuth\Facade\OAuth',
)

Laravel就知道去哪找這個套件了。

然後在’app/config/’底下建立’oauth-4-laravel.php’設定檔:

 'Session', 

    /**
     * Consumers
     */
    'consumers' => array(

        /**
         * Facebook
         */
        'Facebook' => array(
            'client_id'     => '',
            'client_secret' => '',
            'scope'         => array(),
        ),      

    )

);

其中的client_id跟client_secret需要跟Facebook取得,請到Facebook Developers註冊一個app:
上面的Apps => Add a New App => Website => 輸入app名稱 => Create New Facebook App ID => 搞定。
把id 跟 secret複製貼上到這邊。
scopte留空陣列,只會跟臉書拿到基本公開資料。如果想要email的話,就在陣列內加入’email’。
關於權限請參考官網:Permissions with Facebook Login

然後在’app/routes.php’加入你希望的route:
(假設你有個負責會員資料的controller稱為MemberController)

Route::get('/auth/facebook', 'MemberController@loginWithFacebook');

在你希望提供facebook登入的頁面加入:

    Login with Facebook

然後到你的MemberController加入這段程式碼:

public function loginWithFacebook() {

    // get data from input
    $code = Input::get( 'code' );

    // get fb service
    $fb = OAuth::consumer( 'Facebook' );

    // check if code is valid

    // if code is provided get user data and sign in
    if ( !empty( $code ) ) {

        // This was a callback request from facebook, get the token
        $token = $fb->requestAccessToken( $code );

        // Send a request with it
        $result = json_decode( $fb->request( '/me' ), true );

        $message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
        echo $message. "
"; //Var_dump //display whole array(). dd($result); } // if not ask for permission first else { // get fb authorization $url = $fb->getAuthorizationUri(); // return to facebook login url return Redirect::to( (string)$url ); } }

大功告成!按下你剛設定的’Login with Facebook’按鈕,你會看到Faecbok要求授權、之後會在你的網站上顯示從Facebook撈到的個資。如何使用這些個資就看您打算如何應用囉。

Q&A

Q: 雖然很神奇,但這從頭到尾黑箱作業。背後到底發生什麼事我都不知道,要我如何敢照做?

問得好。其實,會這麼神奇是因為…

套件管理使用了Composer,所以只要輸入composer require就會自動下載完畢。不放心的話請到Composer官網逛逛,或是閱讀我之前寫的Composer設計原理與基本用法

除此之外,一般來說載好第3方套件之後,通常你至少需要初始化這個第3方類別、接著設定幾個值之類的:

$coolLibrary = new ThirdPartyLibrary();
$coolLibrary->setParameter($paramater)

但是Laravel提供Service Provider功能,讓package的初始化在Service Provider內完成,然後Laravel又提供Facades功能,讓你可以使用類別靜態函式去操作某個實體。
結果就是你只需要寫這行:

 $fb = OAuth::consumer( 'Facebook' );

你就可以用這$fb變數去進行各種操作…驗證、發送API request、等等。
當然這種靜態函式包裝某個實體的作法,有些人不喜歡、認為這反OOP。參見:讓你少打很多字:Facades。

軟體開發:你不會用到

最近在從事軟體開發時,常有兩種荒謬的感覺。

情境一


為了滿足新的需求,我需要寫一個類別。
總覺得可以多寫幾個函式,創造出某種漂亮的架構…算了,我先寫幾個蠢函式來用好了。
(動手寫code)…。
咦?突然就結束了。已經成功了,這幾個蠢函式已經滿足所有需求了。
不想進一步去改寫成什麼漂亮架構了。

真荒謬,我是不是只做了半成品就交差?

情境二


為了滿足新的需求,我需要寫一個類別。
總覺得可以多寫幾個函式,創造出某種漂亮的架構…算了,我先寫幾個蠢函式來用好了。
(動手寫code)…。
啊,解決一部份問題了,不過這幾個蠢函式果然不夠用。
只好把這幾個蠢函式全部刪掉重寫了。
(動手寫code)…。
多寫幾個函式,創造出漂亮的架構了。解決問題了!
我是不是一開始不應該寫那幾個蠢函式啊?
明明感覺不太夠用卻還繼續寫,果然全部刪掉重寫了。浪費了一些時間。

真荒謬,每次都硬從蠢函式開始寫。根本是刻意在浪費時間?

思考這個問題的時候,找到了一篇相關的文章。
翻譯出來跟各位分享。
原文:You Arent Gonna Need It


你不會用到

「你不會用到」是極限編程的一種實踐:

「永遠在你真正需要的時候才去實作,別預估需要就去實作。」

即使你非常、非常、非常確定你等一下就會需要這個功能,也不要現在就實作。事情通常有兩種發展:
一、你發現根本不需要
二、你發現真正需要的跟一開始預估的差很多

這不是在說軟體的彈性不重要。這是在說,你不應該根據你以為晚點需要的東西去過度設計。

這種實踐有兩個主要理由:

* 節省時間。因為你沒去寫那些最後發現並不需要的程式碼。
* 讓程式碼更漂亮。因為你沒讓一開始那多少有點弄錯的預估去汙染你的程式碼。

RonJeffries提出一個情境說明:
你正在寫某個類別。你剛加上幾個你需要的功能。你知道你晚點會需要其他幾個功能。如果你現在不需要,就不要現在加進去。
為什麼?

「好吧,Sam,你幹嘛現在加上去?」
「呃,Ron,這會讓我們節省一些時間啊。」

除非你我活在平行宇宙,不然你無法現在多做事情,卻在「節省」時間。除非晚點做這件事比現在做更花時間。所以你的意思是:

「如果現在多花點功夫做好它,最後總共花的時間會比較少。」

除非你我的專案長不一樣,不然專案都是那副德性:現在要做的事情總是有夠多。在事情很多的時候還想做更多,是非常糟糕的。

然後除非你我的腦袋構造長不一樣,不然很有可能你最後會發現根本用不著,或是你用到的時候必須重寫、修正這些程式碼。不管哪個發生了,總體來看你都是在浪費時間,還導致你到時無法把真正需要的東西加進去。

「可是,Ron,我現在知道怎麼做,晚點我可能會忘記。」
「所以,Sam,你是在說你寫的類別複雜到你本人也無法維護?」

保持簡單。如果你需要,晚點再加上去即可。如果你不需要,根本別費這功夫了。今天就好好休息吧。

(Photo via Héctor García, CC licensed.)

Composer設計原理與基本用法

相信有在用PHP的朋友近年來常聽到composer這個套件管理工具。
它到底是做什麼用的?又是為了解決什麼問題而存在呢?
要瞭解這個,得先從歷史開始說起…。

PHP最早讀取套件的方法

初學PHP時,最早會面對的問題之一就是require與include差別何在?
require_once與include_once又是什麼?
弄懂這些問題之後,如果不使用framework,直接開發,便常出現類似這樣的code:

// whatever.php
// 這檔案需要用到幾個類別
require 'xxx_class.php';
require 'yyy_class.php';
require 'zzz_class.php';
// ...

然後在其他檔案會出現:

// another.php
// 這檔案需要用到幾個類別
require 'yyy_class.php';
require 'zzz_class.php';
// ...

這樣的結果,會產生至少兩個問題:
1. 許多檔案用到同樣幾個class,於是在不同地方都需要載入一次。
2. 當類別多了起來,會顯得很亂、忘記載入時還會出現error。

那麼,不如試試一種懶惰的作法?
寫一個php,負責載入所有類別:

// load_everything.php
require 'xxx_class.php';
require 'yyy_class.php';
require 'zzz_class.php';
require 'aaa_class.php';
require 'bbb_class.php';
require 'ccc_class.php';

然後在其他檔案都載入這支檔案即可:

require 'load_everything.php'

結果新問題又來了:當類別很多的時候,隨便一個web page都會載入一堆code,吃爆記憶體,怎麼辦呢?

__autoload

為了解決這個問題,PHP 5開始提供__autoload這種俗稱「magic method」的函式。
當你要使用的類別PHP找不到時,它會將類別名稱當成字串丟進這個函式,在PHP噴error投降之前,做最後的嘗試:

// autoload.php
function __autoload($classname) {
    if ($classname === 'xxx.php'){
        $filename = "./". $classname .".php";
        include_once($filename);
    } else if ($classname === 'yyy.php'){
        $filename = "./other_library/". $classname .".php";
        include_once($filename);
    } else if ($classname === 'zzz.php'){
        $filename = "./my_library/". $classname .".php";
        include_once($filename);
    }
    // blah
}

也因為PHP這種「投降前最後一次嘗試」的行為,有時會讓沒注意到的人困惑「奇怪我的code怎麼跑得動?我根本沒有require啊..」,所以被稱為「magic method」。
如此一來,問題似乎解決了?
可惜還是有小缺點..,就是這個__autoload函式內容會變得很巨大。以上面的例子來說,一下會去根目錄找、一下會去other_library資料夾、一下會去my_library資料夾尋找。在整理檔案的時候,顯得有些混亂。

spl_autoload_register

於是PHP從5.1.2開始,多提供了一個函式。
可以多寫幾個autoload函式,然後註冊起來,效果跟直接使用__autoload相同。
現在可以針對不同用途的類別,分批autoload了。

spl_autoload_register('my_library_loader');
spl_autoload_register('other_library_loader');
spl_autoload_register('basic_loader');

function my_library_loader($classname) {
    $filename = "./my_library/". $classname .".php";
    include_once($filename);
}
function other_library_loader($classname) {
    $filename = "./other_library/". $classname .".php";
    include_once($filename);
}
function basic_loader($classname) {
    $filename = "./". $classname .".php";
    include_once($filename);
}

每個loader內容可以做很多變化。可以多寫判斷式讓它更智慧、可以進行字串處理…。
自動載入類別的問題終於解決了…。

但是光上面的code也有15行,而且在每個project一定都會寫類似的東西。有沒有辦法自動產生這15行呢?
我的願望很簡單,我告訴你,反正我有my_library資料夾跟other_library資料夾,你自己進去看到什麼類別就全部載入好不好…?
阿不對,全部載入剛又說效能不好,那你進去看到什麼就全部想辦法用spl_autoload_register記起來好不好…?
我懶得打15行了,我只想打這幾個字:

$please_autoload = array( 'my_library', 'other_library');

可不可以發明一個工具,去吃$please_autoload這個變數,然後自己想辦法載入一切啊…?

ㄟ等等,我連php程式碼都懶得打了,在web領域JSON格式更簡潔。允許我這樣打,好嗎?

{
    "autoload": [
        "my_library",
        "other_library"
    ]
}

然後誰來個工具幫我產生一大串autoload相關的php程式碼吧…,可以嗎?

可以。

Composer登場

首先,裝好composer(本文不介紹如何安裝。)
再來,建立一個composer.json檔,裏面輸入這些:

{
    "autoload": {
        "classmap": [
            "my_library",
            "other_library"
        ]
    }
}

比原本希望的多打了一些字,不過差不多。
再來,在terminal輸入

composer install

執行成功之後,你會看到一個vendor資料夾,內含一個autoload.php。
沒錯,跟你夢想的一樣。你只要載入這個檔案:

require 'vendor/autoload.php';

你需要的所有類別,都會在適當的時候、以適當的方式自動載入。
php再也不會噴error說你「類別尚未定義」了!
這vendor資料夾裏面的一切,都只是php code而已,並沒有特別神奇的地方。只要去看autoload.php的原始碼,就能知道composer到底寫了哪些php code給你。

ㄟ等等,我寫的類別都放在my_library裏面了,other_library都是網路上copy下來的現成類別。我想要用Google API的Client類別、Doctrine資料庫管理抽象層類別、還有guzzlehttp的發送request類別。
我連去下載這些檔案、然後丟進這個資料夾都懶得做了,我根本不想手動建立other_library這個資料夾。composer真那麼神…不如連下載都幫我自動下載?可以嗎?

可以。

查詢一下那幾個套件在「https://packagist.org/」的名稱、還有你需要的版本號。
把剛剛的composer.json改成這樣:

{
    "require": {
        "google/apiclient": "1.0.*@beta",
        "guzzlehttp/guzzle": "~4.0",
        "doctrine/dbal": "~2.4"
    },

    "autoload": {
        "classmap": [
            "my_library"
        ]
    }
}

然後’composer install’指令除了自動載入你的類別之外、還會自動下載你需要的類別、然後自動載入它們。
一樣require ‘vendor/autoload.php’就可以了。composer實在是太棒了。

其實composer解決的問題不只這樣。
類別多了起來之後,各種程式語言都提供namespace功能協助分類。
在有namespace的情況下,PHP社群與composer是如何解決自動載入的問題呢?
這些比較進階的內容,下回分曉。

Laravel確保資料庫正確:transaction與lock

最近在開發上碰到一個request要執行的任務比較多、後面的任務牽扯到第3方API因此有可能fail,此時前面執行的任務需要將資料回溯的問題。

另外還碰到race condition的資料庫資料同步問題:當兩個使用者同時按下某個按鈕時,資料庫的資料會出現問題。

前者需要利用資料庫的transaction功能確保任務全執行或是全不執行、後者需要用到lock/unlock將某些資料表鎖住不讓其他程序修改。

在Laravel中,該怎麼做呢?查了一下,大概整理出來。

Transaction

有兩種作法,第1種使用closure:

DB::transaction(function()
 {
      // do something
 });

第2種也許比較親切,

try {
    DB::connection()->getPdo()->beginTransaction();
    // database queries here
    DB::connection()->getPdo()->commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::connection()->getPdo()->rollBack();
}

在Laravel facades的協助下,這兩種作法都滿簡潔有力的。
要注意的是,在第1種情況下,若是closure要使用到執行closure之前定義的變數,記得使用關鍵字「use」:

DB::transaction(function() use ($user_id)
{
    // do something with $user_id
});

Lock

要保證一次只有一個程序在修改某幾張資料表,以Mysql來說有LOCK跟UNLOCK可以用。Laravel並沒有直接支援此功能,不過這樣變通就可以了:

DB::connection()->getPdo()->exec( 'LOCK TABLES items WRITE, accounts WRITE, orders WRITE' );
// blah blah
DB::connection()->getPdo()->exec( 'UNLOCK TABLES' );

這邊一次用WRTIE LOCK鎖住三張資料表。當然也有READ LOCK可以使用。

在新創公司,我的軟體開發習慣。

在startup工作,經常是在經歷會員數從0到1000、軟體從無到有的過程。

我在這個過程寫code的習慣是這樣的:

  1. 聽完需求,動手隨便寫、能跑就好、有成就感就好、什麼原則都不管、不花時間討論什麼偉大的架構或是未來
  2. 開始覺得不對勁、不整理code之後會死很慘,重構一部份code、補幾個測試
  3. 覺得繼續改善code只是在浪費時間,繼續往下快樂亂寫
  4. 重複以上這個過程

一個網站的beta版,我通常可以在2-4週內讓它上線。
在這個過程中寫出的某些code,老師看到了會很生氣。

其實,不是真的不理會任何原則。我奉行的核心是這兩條:

* 過早最佳化是萬惡的根源。

(Premature optimization is the root of all evil)

* 軟體開發真正的生產力,只能用它帶來的商業價值去衡量。

(Any true measure of software development productivity must be based on delivered business value)

至於怎麼定義「premature optimization」?
如果沒有前輩指引的話,這件事當然就是憑直覺了,所以想怎麼寫就怎麼寫。

這個循環進行幾次之後,會變得更有經驗,下一次開始專案時,在(1. )的所謂「憑直覺亂寫」,實際上會直接寫出更有經驗、更成熟的架構。

就商業上來說,跟現在流行的Lean Startup精神也搭配得很好。

沒經驗就是沒經驗、還不確定的需求沒有辦法針對它去優化、沒碰到問題不會知道如何處理。
不要花太多時間去處理你根本不太確定的事情。

最後附上Jason Fried與DHH所合著Getting Real中的一段話


最棒的設計師跟軟體工程師,並不是技術最好、手指最靈巧的那些人,也不是把Photoshop跟vim用得出神入化的人。他們是能夠判斷哪些事情根本不重要的人。真正的生產力是從這裡來的。

你大部份的時間都花在根本不重要的事情上。如果你能停止這些工作、思考哪些事情根本不重要,你馬上會發揮你從來沒想過的生產力。只要別把精力用在不重要的事情上就行了。

(Photo via Sharon, CC licensed)

Laravel之父:學習出色的design patterns!

Laravel之父Taylor Otwell在2012年接受採訪時談論了自己寫程式的習慣、並表示他最想給軟體工程師的建議就是「學習出色的design patterns」。
採訪原文在:
PHP Interview With Taylor Otwell The Creator Of Laravel PHP 5.3 Framework – Learn Good Design Patterns

Taylor Otwell最讓人驚豔之處在於:他本來是 .NET 工程師、一本PHP書都沒讀過就把Laravel創造出來了!

原文總共有30個採訪問題,後19個牽扯到技術細節。
本文節錄翻譯前11個問題與各位分享,讓大家更瞭解Laravel之父是怎麼樣的人。


跟我們談談你自己

我的名字是Taylor Otwell,我是住在美國的一位26歲工程師。

你如何開始PHP的

一開始,我是為了快速測試一些產品構想才在晚上寫PHP。我幾乎一直在思考新的產品構想,PHP能讓我非常快速地實作並且測試它們。

你能給PHP初學者的最好建議

見下文。

如果有人想成為更棒的PHP工程師,你會怎麼建議?

學習出色的design patterns。這不只適用在PHP。你可以在任何程式語言使用這些pattern。尤其是S.O.L.I.D. patterns 。把這五個徹底學好。這五個patterns會把你帶到新的境界,我每次寫code幾乎都在想這五個。

你讀過最棒的PHP書籍

我沒有讀過任何一本PHP的書。

你最推崇的PHP部落格或是學習資源

我沒有在看特定的PHP部落格。但是我會每天逛Hacker News,看看現在趨勢何在。

你用什麼IDE

我現在用Sublime Text 2的 “dev” 版本。我愛它!我不能想像沒有Sublime Text要怎麼寫code。

你怎麼debug你的PHP code?

我試著徹底對我寫的所有PHP code做單元測試,特別是像Laravel這樣的函式庫。這在之後會省下很多時間,因為我不用在改變某些地方之後重新測試其他部份。沒辦法寫測試的地方,我會從寫「echo」開始。我的測試工具有PHPUnit跟Mockery。

你最欽佩的PHP工程師?為什麼?

在PHP界,我最欽佩Fabien Potencier。這傢伙是寫code機器、永遠用銳利的眼光去追求扎實的架構、同時維護許多大型PHP專案(Symfony與其元件、Swift Mailer、Twig、Silex等等)、經營Sensio實驗室。雖然Symfony跟Laravel非常不同,我還是欽佩Fabien更勝於其他PHP工程師。

你是任何PHP社團的成員嗎?有的話,能談一談嗎?

我目前沒有加入任何PHP社團。不過我正在準備搬去市中心,也許我可以開一個新社團!

你之前是 .NET工程師,為什麼你選擇用PHP而不是別的語言來建造框架

我選PHP因為它幾乎在所有 shared web hosts都能用,而且他的官網說明文件很棒。雖然跟別的語言相比,PHP有點缺陷,但是它的易用以及完整的文件讓它非常適合用來快速開發應用程式。