DDIA閱讀紀錄(4) – 第二章續:天下大勢,分久必合,合久必分

(本次進度: loc 1065 – 1327)

今日讀的段落從data locality開始,declarative vs imperative的query language,再到map-reduce的基本介紹。這次幾乎每個段落都有具體的程式碼供參考,來更進一步使其論點更加具體。有趣的是,我們在這幾個段落可以一直看到乍看之下立場相對的解決方案從光譜的兩側出發,發展到一定程度後,卻又會在某些地方交匯。

例如data locality指的是document-based data model能一次就查詢出一個document的所有相關資料,但relational data model卻會需要進行多次的查詢來重建之。於是relational陣營便加入了可以在資料庫中直接存儲structured data(XML或JSON/BSON)的功能,甚至也可以直接對該structured data內的欄位進行檢索。但document-based陣營日子也不好過,一次就帶出整個document代表著不管你需不需要,一次噴出來的資料就是那麼大,如果只想更新一小部分也不是很有效率。後來就有些實作品開始加入了類似relational的query language和join,例如RethinkDB。

declarative vs imperative的部分,作者就「改變特定元素的背景色」一例,分別用CSS和JS來寫來呈現declarative language與imperative language的差別。雖然他強烈認為declarative language較適合資料庫應用,例如基於relational algebra的SQL query langauge,但仍有imperative language更加自然的情境,例如MongoDB的map-reduce query。但後者後來仍加入了aggregation pipeline以長得很像JSON的方式來引入類似的declarative query language。(題外話,這讓我聯想到ElasticSearch,這種長得很像data的語言我真的 … 不行啦啊啊啊 Q_O)

因此看完這幾個段落後,才讓我覺得「天下大勢,分久必合,合久必分」。作者認為綜合relational與document-based會是不錯的方向:

A hybrid of the relational and document models is a good route for databases to take in the future.

但最終這種集百家之長的東西常常都會變得過於複雜,然後又會有一群人根據自己的偏好取出「好的元素」,創造新的分支出來吧?看看那個C++,D,和Rust。

下一個段落要開始談的graph-based model就是我沒什麼經驗的部分了,令人期待。

DDIA閱讀紀錄(3) – 第二章續:歷久彌新的The Great Debate

(本次進度:location 907 ~ 1065)

上次提到多對一或多對多的資料關聯性對data model帶來的挑戰,接下來的段落更進一步深入了這個主題,揭露了我過去不知道的歷史:由IBM的Information management system為代表的hierarchical model,以及作者稱為「the great debate」,至今仍爭吵不休的relational model與network model之戰。

DDIA閱讀紀錄(2) – 第二章:從Relational model到Document-based model

(本次進度:從location 737到907,這本kindle版沒有與實體書對應的頁數,只好用location number)

首先看看那張精美的data model地圖,除了繪製功力相當高超外,仔細看會發現每個「地點」和「道路」似乎都是有它的道理的。

本章開頭幾個段落相當精彩,首先從relational model於1970年初次由Edgar Codd提出說起。它接下來數十年間奇蹟般地歷久不墜,甚至從企業級資料處理逐漸普及,如交易資料、物流資料、甚至批次處理的資料存儲,甚至現在移動裝置上也有SQLite了。

25 – 30 years –– an eternity in computing history.

我蠻喜歡作者這樣的形容,這確實是項不簡單的創舉。

DDIA讀書會開始啦!

Book cover of Designing Data-Intensive Applications

從本週開始,公司內部新一波讀書會正式啟動。過去個人參加過無數讀書會、技術分享會,最後都會在緊迫的專案壓力下不了了之。這次又有新的一批人熱血充腦聚在一起,何不再嘗試一次?

這次的讀書會叫「Automattic Salon」,這裡的salon可不是造型沙龍,指的是「gathering」:一群人聚集起來,透過對話進行知識交流或娛樂。這次的讀書會主辦人想必也是經歷過不少失敗的讀書會,他收集大家半途放棄的閱讀經驗後,總結出幾個要點當這次讀書會的指導原則:

  • 不要求快,要慢而深入
  • 要為自己而讀,只是聽取他人的讀書心得意義不大
  • 需鼓勵同儕交流

在這樣的方針下,我們開了一個新的內部p2,訂立以下進行方式:

  • 目標每週讀一章
  • 在每週一,主持人會張貼新的章節討論串,以及兩個提問
  • 每個人在讀完後在該討論串張貼自己的讀後心得,以及對提問的回答

以及一個新的slack channel方便較即時、隨興的交流。

因應上次的30天跳繩挑戰成功,我不禁想,如果每天都把自己讀的份寫個總結,會發生什麼事呢?於是決定開啟這個新的每日洗版系列來實驗看看。

寫這篇文章的當下其實我已經讀到第二章了,看能不能利用這個週末先補上。

WordPress堂堂邁入37%,但 … ?

就在這個月初,根據w3techs的資料,WordPress在整個web的CMS佔有率堂堂邁入37%,今天更邁入37.3%,可喜可樂,可喜可樂

但個人覺得上面這張圖真正值得注意的不是WordPress,而是打倒Joomla成為第二名的Shopify。

它既不是開源軟體,也不是general purpose CMS,作為一個單純電商的平台,它從去年7月的1.6%,竟然以急起直追之勢成長足足1.5倍打倒Joomla;而且按照這個速度,除非Shopify突然捲入什麼致命的政治醜聞,差距在幾年內恐怕只會愈拉愈大。

這一方面反映了個人化的電子商務市場之大,一方面反映了老掉牙的「do one thing and do one thing well」可以是很強大的:Shopify提供的功能恐怕還不到WordPress.com所有功能的1%,但他們的事業體是我們的好幾倍大。這也是為什麼我一有機會就在公司內喊著要砍東西而非一直加東西,但短時間內看來我們還是會往繼續加的路線走就是了。

Growth Hacking新手村學習中

自從轉入MarTech(marketing technology) team後,我們的核心任務為何、衡量成效的KPI為何等等一變再變,自Monica堂堂登入以來,最近整個團隊的定位終於逐漸塵埃落定:

Growth Hacking

義 … 義大利?

聽到的當下我不只是滿頭黑人問號而已,簡直是懷疑人生。我本來就不懂marketing了,現在居然還來個更潮的觀念,試圖把我已經被顛覆到無以復加的日常工作再翻個幾番。沒辦法,身為MarTech的squad lead之一早已沒了退路,只好領著大夥每週進行1~2小時類似讀書會的學習,嘗試一窺堂奧。

本篇以流水帳的方式做這週的個人學習紀錄,希望堅持一陣子後,終能看到隧道盡頭的一點光亮。

用nginx + docker配置多個WordPress站的基本設定

前幾天和幾位朋友聊到WordPress測試環境的配置。有時候為了測試更貼近實際使用狀況,單靠ChassisVVV的開發環境還遠遠不夠,還需要實際將功能上到有公開網域的WordPress站上才行。這時我比較常用的方法是直接靠nginx做reverse proxy將某個子網域對應到一個WordPress Docker容器,這樣既不用擔心測試中污染環境,從配置到銷毀都快速又乾淨。例如https://jptest.southp.dev/就是我拿來測試Jetpack用的(空空的,沒啥好看的啦)。

因為我只是自己測試用的,所以一直以來我都只用一些很基本的手法來做這件事,沒想聊一聊發現好幾個人都跟我一樣,不需要用到這麼多複雜的套件,只想要非常簡單的方法就好,所以寫這篇文章簡述一下。

我們與PHP的距離(二): 任性的大小寫

本系列專為從PHP之外的語言開啟碼農人生、卻因命運安排整天與PHP為伍的人撰寫,收集一些從其他語言的角度看來不可思議的設計。如果能讓在讀這篇文章的你在實務上踩到而懷疑人生前就釋懷,就是我莫大的榮幸。

前言

前篇gethostbyname(),本篇討論少見於PHP之外的設計:varying case sensitivity,也就是某些情況下大小寫相關,某些情況下大小寫無關。總之,就是任性。

可能因為我個人有經年累月的大小寫相關的程式編寫習慣,再加上linter層層把關,我大概兩年多才發現有這個特性,當下簡直是晴天霹靂、茅廁頓開,在這非黑即白的大小寫相關性世界,PHP竟仍能為我們開一扇窗;彷彿在提醒我們,看待世間萬物切勿抱持成見,才能看見真實。

常有人說PHP是如詩般的語言,這,何嘗不正是其獨有的詩意呢?

嘴夠了,進入正題

更精確來講,PHP的大小寫相關性是:

  • 函式名、命名空間名與類別名大小寫無關
  • 變數名、常數名大小寫相關

啊啊啊啊啊啊啊啊啊啊啊啊啊

大部分的時候這都只會造成一些小驚喜,像這樣:

class Foo {
    const ABC = 'I am a constant';
    static function bar() { ... }
}
$poetry = 'I am a variable';

Foo::bar();  // 可以
foo::Bar();  // 嗯,有何不可
print_r( $poEtry ); // 不行喔
print_r( Foo::aBC ); // 討厭,就說不行了,都欺負人家 ...

但一個沒站穩,玻璃心還是會摔碎的。

我們與PHP的距離(一): gethostbyname()

前言

自從加入a8c,PHP作為常備語言之一,時至今日仍然像顆出奇蛋一樣止不盡的驚喜。天底下沒有完美的語言,但至今確實沒有任何一個我寫過的程式語言比PHP讓我感到更『魔幻』。本系列專為從PHP之外的語言開啟碼農人生、卻因命運安排整天與PHP為伍的人撰寫,收集一些從其他語言的角度看來不可思議的設計。如果能讓在讀這篇文章的你在實務上踩到而懷疑人生前就釋懷,莫大的榮幸。

祝各位天天PHP,天天開心。

進入正題

首先來看看今天的主角:gethostbyname() 在文件中是怎麼描述的吧:

gethostbyname ( string $hostname ) : string

Returns the IPv4 address of the Internet host specified by hostname.

舉例來說:

php> print_r( gethostbyname( 'softman.blog' ) );
192.0.78.25
php> print_r( gethostbyname( 'localhost' ) );
127.0.0.1

很簡單吧。這基本上就是一個gethostbyname()系統函式的包裝,

但問題出在它的回傳值設計。根據官方文件:

Returns the IPv4 address or a string containing the unmodified hostname on failure.

『當錯誤發生時,會回傳無修改的hostname引數』

……………..

這神設計有兩個問題。第一,和許多PHP函式的錯誤行為相悖;第二,複雜的錯誤處理讓這個函式很難正確使用。如果你認為:

$hostname === gethostbyname( $hostname )

這樣就結了,那就太小看PHP惹 …

l()有什麼不對

話說PHP因為不像JavaScript內建的log函式庫就挺不錯,不同的源碼中總是可以看到自己的log函式。最常見的不外乎是可以印出任意個引數值到error log / stdout / stderr,或是印出第一個引數後回傳之。

誒~但可能是大家都想盡量少打些字吧,我發現這類函式經常被命名為 l()。對,就一個一柱定海的l

是很精簡啦,而且l這字看久也蠻美的 … 但個人認為這並不是一個好名字。為什麼?因為不夠明顯啊。這就有點像C++為什麼要引入static_cast reinterpret_cast啥的來取代C-style cast,要特別留意的東西應該要盡量設計成引人注目會比較好。

基於這項理由,我自己在用的是mango()guava()litchi()

……………….

……………….

真的啦,有code為證:

function mango( $val ) {
    if ( is_null( $val ) ) {
        return 'NULL';
    } elseif ( false === $val ) {
        return 'FALSE';
    } elseif ( true === $val ) {
        return 'TRUE';
    }

    return print_r( $val, true );
}

function guava() {
    $arg_strs = array_map( 'mango', func_get_args() );
    $log = join( ' ', $arg_strs );

    error_log( $log );
}

function litchi( $arg, $label = 'log value:' ) {
    guava( $label, $arg );
    return $arg;
}

說真的,自從我把這些log函式從WTF系列改成這台灣味的水果系列,整個人debug起來心平氣和,修為都提升了呢 🤪

而且另外的好處是很好搜尋啊。大家在提交源碼前相信公司都會要求把不必要的debugging log都拿掉吧?(啥?你們公司不用?塊陶啊~) 這樣只要ag guava就一定能找出所有的debugging log了呢。雖然也可以用ag '\bl\('找到所有的l()呼叫,但這打起來手就癢癢的,沒這麼順暢呢 … (個人因素

我在某次working tips分享中分享了這個小撇步,會後有人漲紅著臉拿了這個給我看:

function 👻( $val ) {
if ( is_null( $val ) ) {
return 'NULL';
} elseif ( false === $val ) {
return 'FALSE';
} elseif ( true === $val ) {
return 'TRUE';
}
return print_r( $val, true );
}
function 💩() {
$arg_strs = array_map( '👻', func_get_args() );
$log = join( ' ', $arg_strs );
error_log( $log );
}

嗯 … 真是超級明顯又好搜尋呢