What have you found for these years?

2009-01-07

少女漫畫

咳咳,終於狠下心來做點其他事。好像覺得舒服不少 XD
anyway...

剛剛稍微看了一下 suckcomic 板上一些少女漫的討論,
感覺對於漫畫分類有所誤解的人,似乎真的很多。
一方面是本來就沒有明確的分界,另一方面大概是現在也越來越多
界線不明確的漫畫,題材五花八門吧?

關於少年青年,有一篇四格非常傳神,相信大家都看過 XD
剛剛 google 了一下,果然第一筆就找得到,而且關鍵字只要下:

「30 秒就懂」

不給連結因為太有名,太好找了 XD

當然了,要簡短易懂,多少就會有些偏頗。所以傳神歸傳神,
笑笑也就算了。不過說到少女漫畫的話,我就真的是相當不了解了...
當然這也不是在說其他分類就很了解,只是相對來說是這樣。

*

屈指算算我看過哪些少女漫畫?真的幾乎沒有耶。剛剛注意到
印象最深的可能是庫洛魔法使吧?前幾年曾經有稍微複習一下,
我覺得裡面的人真的還滿混亂的....... 這是題外話啦。
wikipedia 裡查 CCS 也查得到,被分在 Culture 那一欄裡。
足見這一部確實是有很大的影響力在。

其他... 其實有好幾個都看過一點點,真的有完全看完的,幾乎沒有。
另一個好像有看完的是玩偶遊戲。不過這兩部的動畫跟漫畫都不同,
我有看完的好像都只有漫畫,動畫都太長了...

如果問我為什麼,現在大概只想到一點,就是會讓我感興趣的內容並不多吧。
例如也聽過有人(嗯,確實是有人 XDDDD)說貧窮貴公子是經典?
可是我覺得很難笑... 可能是因為裡面的人太耀眼了? XD
也只看過一本的樣子,不怎麼感興趣就沒怎麼注意。

其他瞥眼過去,聽過的大概只有 3%, 更別談有沒有看過了...

不過講真的,現在處於模糊地帶的漫畫真的太多了,
所以到底是什麼分類,也真的是笑笑就好了。只是看到說:
「OO 漫畫都是 XX」,那個感覺就,很囧吧 XD



==

想到很多年前在看玩偶遊戲的時候,我忘記那時候是跟誰在講話了,
是直接對談呢,還是中間又隔著另外一個人?總之就是聽到他說,
看什麼玩偶遊戲,要看北斗神拳啊... XD

不過這我也完全沒看過。只知道後來看到一兩話蒼天之拳的動畫,
我敢說這肯定是分類在搞笑動畫裡面 XD 從頭到尾就只有一個字:

「蠢」

...還有碰友? XD

DataMapper 地雷

class Pet
include DataMapper::Resource
property :id, Serial
property :model, String
end

Pet.first # stack level too DEEP!

因為原本的 Pet#model 是不能被改寫的,現在變成 property 就爆炸。
解決辦法:

property :_model, String, :field => 'model'

.......有點笨!

還是搞半天才想到是這問題!之前曾經用到 object_id, 當然也是死...
不過因為這本來就是 ruby 的 method, 看一下就知道原因了。
這 model 可就不是了... 這可不是改寫 :send 可以比擬的,
:send 本來就不應該被改寫,這是基本常識...

天,好累

總覺得有種虛脫的感覺,但事情還沒弄完啊!!
來看看要怪誰?datamapper 的 Collection#destroy! 有陷阱,
參考:http://blogger.godfat.org/2009/01/sql.html
不小心把一些測試資料幹掉了,感到很有歉意,一百多張耶,
幾乎是所有測試資料的一半了 XD 只好先用另一種方法解決問題,
然後回來後開始挖 dm-core 要怎麼改比較好。

中間吃飯也覺得有點累。
講真的,對我來說,一切就是方便就好,有什麼小地方不好,根本就沒差。
或是該說,我並不想麻煩任何人,能改好的我就改好,不能的就算了。
所以說有剩的東西我會盡量吃完,吃不夠的東西我也不會再叫。

that's all.

拜託真的不要一直叫人斟茶或是補充,叫了你又不吃不喝,我看了又好累...
感覺根本不能安靜吃飯啊

回來想想真的覺得好煩,每次都這樣... 就不能簡約一點嗎??
我在用的我在吃的我在住的,我開心就好啦,幹嘛一直干涉啊!
真的是永遠講不聽耶...

捷運上的小事就趕快忘掉。

後來開始修改 dm-core, 加錯誤輸出很容易,加 test 搞半天。
壞掉的 mock 也看半天才修好。處理好 sam/dm-core, 又在想是不是應該
修 dukbb/dm-core 才對?只好再 clone 一份下來,修修改改,
rspec 的 lambda 問題又搞了有夠久,好幾個小時搞不好?

總算用 workaround 繞過去後,又在想是不是應該寫一個 patch 就好,
另一個用 merge/cherry-pick 之類的抓過去比較好?而 merge
大概會整坨一起進去,那 cherry-pick would be rescue?

又查到撿櫻桃需要在同一個 repository? 只好 fetch 看看,
從 sam/dm-core 設 remote tmp 指到:
/home/godfat/projects/gits/dm-core-dkubb/.git
然後 git fetch tmp, 結果居然還強迫 merge origin/master @@
這下大概毀了,下次要重新 clone 一份,因為我不知道發生什麼事了...

說 git 不 friendly 大概也是真的,太複雜,太多概念,上手要一段時間。

接著總算撿到櫻桃了,發現是針對 sha1 commit, 而不指定 branch?
也搞不清楚這樣對不對,後來想想乾脆重寫就算啦!

輸出 git format-patch, 發現一個 commit 生出一份 .patch,
也不知道這樣要怎麼丟給別人比較方便... 整份 diff 出來又沒有 log.

還有發現 git send-email 居然是用 /usr/sbin/sendmail 去跑 @@
結果 gmail 收得到,但是 cc 卻進 spam 了 XDDD
大概是因為他假設自己只會用自己寄,而不是別人吧。

然後整理到 gist 上,寫到 lighthouse 上,實在很耗費精神...
一來要寫英文還是比較累,寫出怪怪的句子實在不好意思。二來又要想用詞妥不妥當...

累死了 orz

下次不要 report 好了?默默 fork 然後送 pull request 比較省力...
又不是 full time 搞這... 只是做 lib / framework 還是比較好玩 :s

先這樣,其他的其他地方說。

2009-01-06

不熟 SQL 的下場又一

就是做了這件事:

Pet.all(:limit => 10, :offset => 5).destroy!

然後所有的資料就都被刪掉啦... 因為生出來的 SQL 是:

DELETE FROM "pets"

根本完全看不到 LIMIT 也看不到 OFFSET... 另一方面,
我也希望 LIMIT 可以省略,不然只好 LIMIT 100000000...
但 SQL 好像也不允許省略?

會想這樣做的原因,是希望保留相同條件的資料,至多 n 份。
如果 DELETE 可以用 OFFSET, 那就 OFFSET n 即可,
問題是居然不行!!!囧,害我誤砍一堆資料......
幸好不是 production data, 只是長年來的測試資料... 沒了 :s

為此想說希望 DM 不要忽略 LIMIT/OFFSET, 寫 patch 只要幾分鐘,
但寫 test 就搞死人了... sam/dm-core 的 test 太混亂,不寫了,
只是他的 mock 我看半天才把他修好。這種測試法我個人覺得真的很爛。

而 dkubb/dm-core 的 spec 則漂亮乾淨太多了,雖然數量有點恐怖...

Finished in 306.702122 seconds

10242 examples, 0 failures, 3322 pending

這還是關掉 PostgreSQL 和 MySQL 的結果咧。打開的話大概需要三倍時間,
在我可憐的 macbook 上可能要跑 900 秒吧... sam/dm-core 的 test 是太少,
但 dkubb/dm-core 的 test 也未免太多了吧 @@

而且沒試出跑 single test 的方法,每次都要跑全部,真的很累...
值得高興的是,dkubb/dm-core 的 test 不用修,因為沒有奇怪的 mock,
還有這麼多 test 中沒有一個用到 destroy! with LIMIT/OFFSET,
希望這 patch 或是之類的結果可以加進去... 這樣至少會噴出錯誤,
而不是整個就這樣給我砍掉...

相關 code 放在 gist 上:
http://gist.github.com/43742
因為 lighthouse 真的不會用,貼出去的排版都是一團糟。

rspec 的問題寫在另外一篇:rspec bug???
http://blogger.godfat.org/2009/01/rspec-bug.html



查詢途中看到這個:
Re: Deleting, skip the first n records
http://lists.mysql.com/mysql/202339

呃,是個方法。於是要先取出目標時間,然後再根據此做比較。
變得比較複雜些...

def compact! n = 3
last = user.photoships.first( :friend_id => friend_id,
:order => [:created_at.desc],
:offset => n )

return unless last
last = last.created_at

# offset won't work on delete!!!!
user.photoships( :friend_id => friend_id,
:created_at.lte => last ).destroy!
end

rspec bug???

updated:
發現跟 dkubb/dm-core 有關的樣子... 唉
最後只好這樣寫:

begin
@model.all(kind => 3).destroy!

rescue => e
e.should be_an_instance_of(ArgumentError)

end



lambda{f}.should raise_error(ArgumentError)
這怎麼叫都會變成說 nothing was raised.

lambda{f}.should raise_error(ArgumentError, 'blah')
這樣會有東西出來,卻是說:

expected ArgumentError with "blah",
got #<ArgumentError: blah>

但是用:
lambda{f}.should_not raise_error(ArgumentError)
又會告訴我:

expected no ArgumentError,
got #<ArgumentError: blah>

但如果是:
lambda{f}.should_not raise_error(ArgumentError, 'blah')

就完全沒錯了????

啥鬼???第一次試改就捅這麼大的摟子??我要怎麼繼續試啊??
不能用 ArgumentError??

未來的訊息 XD

Lin Jen-Shin wrote at 1:36pm tomorrow

非死不可的訊息... 滿蠢的,大概有考慮到時區裡的「時間」,
沒考慮到「日期」吧,結果就變成明天了 XD

說到這,我還滿討厭那種「OOO 以前」那種形式的 timestamps,
因為我常常會想整段 copy 下來備份,那就變靜態資料,十年後的
10 分鐘前誰知道是什麼時候啊???

不過現在真的很多地方愛這樣寫哩...

github 好些,他是這樣寫:

<abbr class="relatize" title="2009-01-05 22:10:55">11 minutes ago</abbr>

雖然顯示是顯示 11 分鐘前,好歹我還有個標準 timestamps 在那邊可以查閱。
不然我實在很討厭自己算 11 分鐘前是什麼時候...

2009-01-05

single-user only rubygems

setup runtime:

bash: (~/.bashrc)

export GEM_HOME=$HOME/.gem/ruby/1.8
export GEM_PATH=$GEM_HOME


fish: (~/.config/fish/config.fish)
set GEM_HOME $HOME/.gem/ruby/1.8
set GEM_PATH $GEM_HOME


setup config:
echo "gemhome: $GEM_PATH
gempath: - $GEM_PATH" > ~/.gemrc


now system gem would not mess-up your user gem.

2009-01-04

google, gmail, and github

如果說 google 改變了搜尋網站的方式,而 gmail 改變了使用 email 的方式,
那麼或許 github 也有著改變 open source project 運行的方式也說不定。

可以讀一下 Michael Klishin (merb core developer) 的這一篇:
Re: Happy new year and... moving Ruby development to Git?

一些他自己使用 git, mercurial, bazaar, 和 darcs 的經驗。
雖然 mercurial 和 darcs 我都只拿來抓程式,而 bazaar 從來沒用過,
不是很清楚一些使用上的細節。但我還滿同意他所說的:

實際上用哪個都沒有差,重點是 mercurial, bazaar, 和 dacrs 都沒有 github.

[quote="MK"]
Everything you read above simply does not really matter.
Because GitHub is only available for Git. Hg, bzr, darcs all lack github.
[/quote]

我想目前除了 host 以外,唯二我可能會考慮掏錢的網站,大概只有 gmail 和 github.
(因為我想 google search 不太可能會收費,就跳過了 XD)
意思就是無可取代(目前),而且很重要很好用。

[quote="MK"]
Seriously, what made a lot of projects in the Ruby community switch to
Git? The fact that it is "new hotness"? Performance? The fact that Hg
and bzr are in Python? Linus Torvalds fanatism? Marking efforts of
Chris, Tom, PJ and co? No. Ease of collaboration that is not really
possible without GitHub at this moment.
[/quote]

pull request, fork queue, network, collaborators,
watch, follow, comment, service hooks (我沒用過),
source browse, 甚至連 html website 都能 host, 像是:

http://godfat.github.com/

只要建一個 repository 叫 YOUR_NAME.github.com 即可,完全自動。

這些是 git 的優點嗎?或許任何一套 distributed source code management,
都能夠掛上這些功能。問題是只有 github 提供了這樣的服務給 git 使用。
而且任何人都能免費使用,免費的空間是 100MB, 我用了約 20MB, github 也說明,
這個限制只是避免別人濫用,需要更多的免費空間,還可以再跟他們討論。

這就讓我想到 lukhnos 所提到的

[quote="lukhnos"]
高科技(例如 CMS, VCS, BBS, DOS 等)往往只是更突顯問題的本質,
而不是解決本質……
[/quote]

在大量引用工具來企圖解決問題的同時,也確實往往會引起更多更多的問題。
那麼究竟要不要引用?

要!我肯定會這麼說。

其實這也正是解決問題的有趣之處。尋找更好的解決方法,而不是真的解決問題。
我知道這或許有些不切實際,但是做事情還是需要一些有趣的事,否則枯燥乏味之下,
只是在減少士氣與減少 project(或許也包括 developers)的壽命罷了...

p.s.

只欠 issue tracker 啊!怎麼不拿 redmine 去改一個把 lighthouse 打爛? XD
lighthouse 我每次看版面都是爛的,而且免費版的限制太大了,根本不能用...
帳號問題又超煩的 :( redmine 好用太多了。

2009-01-02

這真的想讓人罵髒話...(rails/merb)(2)

針對這篇的一點想法:

Merb/Rails merge, or Why should merbists be happy?

因為這篇其實解釋了不少很容易會有的疑問,其中幾點確實就是我所質疑的。

> Why merge when we are about to win?!

如果不考慮合併的困難,直接假設合併會有很好的結果,
那我想這一篇的陳述就會是對的。力量確實需要集中,
這也是為什麼現在一堆合併併吞合作等等的事情發生...

很多旁觀者認為 rails 跟 merb 合併是一件很合理的事情,
因為為何要競爭?如果大家都是走在同一條路上的話。這樣看來,
確實是沒有錯,再合理也不過了。問題是,merb 和 rails 內部結構
幾乎完全不一樣啊!打個比方,你要 gcc 跟 visual c 怎麼合併??
對啊,對 client 來說,他們都是 c compiler, 如果遵照標準來寫,
對 client 來說根本什麼也不用改,或是只要改小小的地方即可。

但這種合併可能發生嗎?

我覺得這只是讓 stable merb 往後延長至少半年。
不可否認,現在的 merb 還是大有問題啊...
又或是,反正 datamapper 也還沒 1.0, 可以順便等等 dm 呢?



> What does Merb win by being merged into Rails?

除非 merb 掌權,不然這些都是 rails 的好處吧...



> Why not merge Rails into Merb?

這是我最不同意的一段。我完全不覺得把 rails 改成 merb like 會比
把 merb 改成 rails like 要來得簡單...

至於名字方面,換個新名字其實就是希望捨棄包袱,不要去搞相容介面。
去除此的話,我相信 rails 是個好名字。



> You are killing innovation by killing the competition

這個... 我不覺得這種 competition 有什麼必要啦。
所以沒什麼意見。



> You screwed us over and now I have to go “back” to Rails

叫 alias_method_chain 去死,讓所有用到這東西的 plugin 都掛掉,
and no more other comments.



> Rails 3.0 won’t even be as good as Merb 1.x

半年甚或是一年又過去,再來看這件事吧。
重點還是要怎麼合併,以 rails 還是 merb 的方式走。



> The Rails team won’t let you do what you
> have to do to merge Merb into Rails

well, let's see...



> DHH is a jerk

no comments, i don't know him well,
but it's interesting to hear that.



總之,這篇確實解釋了很多東西。剩下的問題大概只有一個,
就是究竟能不能做到吧。我覺得比較重要的還是,讓 stable 這件事,
又再度往後延長很長的一段時間....

如果 google 是因為這個原因而不選擇 ruby, 完全能理解啊...

safari 問題再一個

我把系統音效輸出改到 audiofire 2 的話,有時候右邊會有波波聲。
發生原因不是很清楚,總之就是盡量只讓音樂輸出到 audiofire 2.

不過玩遊戲想接喇叭,還是輸出到 audiofire 2. 結果 safari 瘋狂波波叫,
firefox 倒是一點波波聲都沒有。別問我為什麼,問 apple 啊...

只好關掉 safari, 還是用 firefox 打 epic war 2.
以前都是用 safari 跑 flash, 因為比較順...
現在感覺都差不多了,反而 safari 有音效問題。

2009-01-02

來不及了,所以當然是不去了 @_@

*

[...]

看你們講得煞有其事的樣子,剛開始我還真以為是故意的咧 XDD
畢竟說神山健治最後來個大搞笑,感覺不是不可能... XD

對了,說到這裡,以前總是會覺得一定要告訴我啊 XD
不過後來有些東西看多了,也開始會覺得...
還是不要知道好了 XDD 也開始可以理解,
為什麼有些事還是不要點破好了... XDDD

可見得大概已經有些受到污染了吧 XDXD

[...]

*

剛剛在書店裡晃了幾下,不自禁就開始出神了,總覺得想到很多事。
後來一晃眼看到了快樂王子,心中一顫,隨即覺得還真是出現的時候。
不過還真厚啊,這是全文嗎?

記得那時候反覆翻了好幾次,不過其實沒有很細讀,
因為看過好幾次了,耐心沒那麼好... XD
只是只是,想要一些感覺罷了。

...

唉。

*

昨天打了一整天的 Epic War2...
http://www.kongregate.com/games/rudy_sudarto/epic-war-2

基本上我覺得如果說這遊戲的出發點就是消耗玩家的時間,
那他還真的成功了。太過無聊的遊戲,兩三下就讓我受不了了。
但這遊戲又還沒到太無聊,卻又真的很浪費時間...

一來打法固定,肯定是用弓箭打全場,然後 mana boost 到 9999 (max),
接著就是一直出幾個固定的單位,that's all...
尤其打到 THE END 那個 boss, 我只能一直出 hobbit, 還有 bomberman,
hobbit 因為生很快,所以可以一直衝到 the end 前面,the end 就會停下來攻擊。
一次攻擊大概會死十幾隻 hobbit, 還有三隻 bomerman, 都是平均分佈的死法 XD
因為 boss 攻擊範圍太廣,所以有些 hobbit/bomerman 可以衝過去,
有些就會半路就死... 這可能是最好的打法,因為其他單位大概也都是一擊必殺,
那又何必用高昂的單位?就這樣一直卡 the end, 搭配主堡的弓箭,
還有一段時間可以生一隻的 forest guardian, hp 16k, 可以真正擋住 the end.

就這樣慢慢消耗 the end 的 999k 的 hp, 打到讓他停在主堡前面一點的地方打贏了...
所以算是險勝吧,再靠近就要被他炸翻了。其他小敵就不用說了,都是雜魚而已...

然後除了 human 以外,還有 elf 和 orc. 我先把 human 打到只剩 castle
還沒升滿,其他都升滿了。接著換 elf 打到全部升滿... 接下來是 orc @@
要打三倍.... 慢慢打前面的章節練等級。真的是有夠浪費時間 :(

不過也罷,我也確實需要一些無聊的東西浪費時間...

好遊戲打很久也可以讓人覺得很滿足。像這遊戲打好久就會覺得空虛 XDD
不過還是打了。don't blame me... orz

2009-01-01

2009-01-01

延續:「人人要跨年我卻從早上寫程式到半夜不止歇。這晚點再講。」

*

唔唔,看來會打錯一陣子 08 了。

*

剛剛想到其實我說「你是認真的嗎」這句話時通常是沒什麼預設立場。
不過這樣講也不怎麼誠懇,因為主要大概還是永遠的試探語氣,
可以往任何台階下的感覺。當然,每個受話者各自是怎麼想的,就不得而知了。

沒什麼反應是一喜與一憂。喜於不用改變什麼,憂於是不是又老在給人碰釘子了?

*

好無趣?那也許是永遠找不回來的情緒。對此倒是早就很認命了。
也常常在想,或許那些說來可能會有所改變的事情,實際上也做不了什麼。
當然,這種事倒不是靠想像就有辦法模擬的。只是如果說服自己是這樣,
那可能會比較心安理得一點吧。就好像把過錯全部歸咎於宿命似的...

*

其實時間也沒什麼意義。我向來不覺得有什麼階段階段的。
儘管會有人喜歡說進入「高中」怎樣怎樣,進入「大學」怎樣怎樣,
進入「研究所」怎樣怎樣,進入「社會」怎樣怎樣。
老實講,我看不到什麼改變。如果我們沒有曆法,看到的就只是日出與日落。

哪有什麼適應問題?根本就沒改變什麼啊。

*

常常覺得跟有些人說話好累。
一樣的對話一直在重複,講到很煩。
一樣的對話一直在重複,講那麼多次你還是要誤解。
一樣的對話一直在重複,就算到最後你還是搞不清楚狀況。
於是我只能下一個結論,因為差異太大,所以永遠無法理解。

我不是故意要失去耐心的,只是這真的很煩...
尤其是當你看到別人表現得好像很了解,你不用說!我都知道!
但結果全是錯的。這多讓人沮喪。也許以訛傳訛就會這樣繼續下去。

後來都懶得解釋,也更加重這樣的狀況。唉,不過有差嗎?
如果代價如此高昂的話...

*

真的看不懂電腦線圈嗎?不試著看完嗎?真失望... XD
難得這是我覺得不比攻殼差的動畫,而且比較好懂說。
不曉得是哪個點沒抓到..?

*

宵夜還是冬眠?

cache (4)

人人要跨年我卻從早上寫程式到半夜不止歇。這晚點再講。

為了做朋友的相片 cache, 連朋友 relation 都要做。
所以做了 self-referential, 然後發現這樣做好像只是單向,
而不是雙向的。平時 A => B 或 B => A 的關係是固定的,
然而 self-referential 卻會變成 A 是 B, B 也是 A,
因此似乎變成需要兩筆相反的 edge?

但我覺得這樣做很蠢,所以改成用兩筆 query 來組成結果。
也就是 A => B, B => A 各做一次,然後合併起來。

  def friends
friends_true + friends_false
end

不用介意什麼是真假朋友,只是為了讓 !A 為 B 而這樣做而已。
畢竟如果用 n * -1 的話,名字裡可不能用 '-' 哩。

於是真假朋友這樣做:
[true, false].each{ |b|
friendships = "friendships_#{b}".to_sym
has n, friendships,
:class_name => 'Cache::Friendship',
:child_key => ["user_#{b}_id".to_sym]

has n, "friends_#{b}".to_sym, :through => friendships, :class_name => 'User',
:child_key => ["user_#{b}_id".to_sym],
:remote_name => "user_#{!b}"
}

DM 有個地方比 AR 煩,就是改寫一個名字,大概就要全部改寫,
因為預設的值都怪怪的... 於是會顯得稍微 verbose 一些。
這個缺點希望在日後的版本中可以改進。這點 AR 是做得比較好。

friendship 就很簡單只是:
belongs_to :user_true,  :class_name => 'User', :child_key => [:user_true_id]
belongs_to :user_false, :class_name => 'User', :child_key => [:user_false_id]

有了這個後,就可以開始 cache friendship 了。
require 'cron/ffbapi'

module Sync
module User
module_function
def friendship user
Ffbapi.use user.id
Facebooker::User.new(user.id).friends.each{ |friend|
# left?
Cache::Friendship.first( :user_true_id => user.id,
:user_false_id => friend.id ) ||
# right?
Cache::Friendship.first_or_create(
:user_true_id => friend.id,
:user_false_id => user.id )
}
end
end
end

增加的部份是多個 User/Photo 的 module, 因為這次是要以 user 當主角。
Ffbapi 是 facebooker 的 adapter, 拿來銜接樂多朋友的 api.
這邊我幹了不少蠢事:

1. 灌了新版 facebooker:

gem install mmangino-facebooker --source http://gems.github.com

因為直接用 plugin 上的會需要 rails 環境,亂改一氣是可以弄起來,
拿掉(或說補上)RAILS_ROOT 和 RAILS_ENV 就可以了。不過實在很討厭這樣做,
所以還是灌了 gem, 而 rubyforge 上的 0.9.5 好久了,想用新版...

結果灌了之後怎麼試都回答我 api key 錯誤。而 plugin 版卻可以!?
而且跑的速度變好慢!試半天,就在快要放棄時才忽然想到,啊咧,plugin
我改過啦!api url 從 facebook 改成樂多朋友囉。所以才說不想改 plugin 嘛,
這樣要換新版或是移植什麼的都變得好麻煩。

不過會這樣搞半天有一個很大的原因是 api 本來也是我寫的,害我一直翻程式碼出來,
看半天覺得沒有錯啊!結果造成這個大盲點。其實我覺得所謂 pair programming,
最好的地方就是可以避開這種極蠢的盲點。就算不大會寫,也應當記得要改 url.

於是照著 facebooker 的 adapter 做個 subclass, 只改兩個路徑即可。
又發現奇怪,為什麼朋友資料抓回來都怪怪的呢?這又是另一個盲點,
session_key 根本都還沒建立,而我 api 本來就會忽略這個錯誤,
所以這邊也搞半天才想起來 session_key 沒設。參考了 source code,
發現其實很簡單,去掉 rails plugin 的骯髒手法外,facebooker 似乎還算
可以修修改改:

s = Facebooker::Session.new api_key, secret

就可以產生一個全新的 session. 而:

Facebooker::User.new id

就有 user 可以用。第二個參數是 session, 所以:

Facebooker::User.new id, s

即可產生可以用 api 的 user. 不過也可以設在 current session 中:

Facebooker::Session.current = s

那麼 user 會自動取得:

Facebooker::User.new id

就有 session 可以使用。adapter 的套用:

Facebooker.current_adapter = Ffbapi.new({})

那個 hash 不要管,一些 config 而已,例如 api_key 之類的。
不能省略讓我好失望 XD

接著就可以這樣建立 session:
Facebooker::Session.current = begin
environment = YAML.load(File.read('config/thin.yml'))['environment']
config = YAML.load(File.read('config/facebooker.yml'))[environment]

Facebooker::Session.new(config['api_key'], config['secret_key'])
end

根據 thin 的 environment 來決定要用哪個 env, 我所有的都這樣寫。
再加上偽造的 auth_token/session_key:
  def Ffbapi.use id, s = Facebooker::Session.current
s.auth_token = id.to_s
s.secure!
s
end

這個就是小撇步了,原本的流程是:

1. auth.createToken
2. login
3. auth.getSession

不過在 ffbapi 裡,login 的部份是完全沒用,改以 cas 完成。
http://en.wikipedia.org/wiki/Central_Authentication_Service
於是這邊的流程會變得有些弔詭。暫時先不深究,目前重心放在 cache 上。
這邊要完整實作還有一段距離... 如果我沒記錯的話,呼叫 auth.createToken 後,
cas 應該要有辦法取得剛剛的 token, 然後在 login 後丟回給 client.
也就是說需要動到 cas server, 目前這部份不是我處理,那就先跳過...

觀察這邊的流程其實也費了我不少功夫。facebook 的認證算是滿完善的。
當然啦,我想大部份的認證應該都很完善,只是這方面我不熟,也是看很久才搞懂
為什麼要做得這麼複雜。每一個小細節都是防止一種攻擊法,全部加起來就算滿健全的。

所以這邊我暫時作弊!跳過 auth.createToken, 也跳過 login,
直接用 auth.getSession. 那這 session 怎麼產生呢?答案是根據 auth_token
建立。app 丟來什麼 auth_token, 就照樣做成一個假的 session_key.

也就是說,這使得 app 可以偽裝成任何人!這個呼叫應為危險的,
所以暫時只開放 private ip 連線... 其他 ip 一律丟 403 回去。
而上面提到的:

s.secure!

就是拿剛剛的 token 做成 session key. 成功偽裝...
這樣做的原因是朋友資料是看 session key, 而不是 pass uid.

回到 Cache::Friendship, 於是需要偵測真假(左右?前後?),
如果有缺的話就幫他補上,哪一個方向都無所謂。

這邊欠 remove 的動作,會使得絕交不會反應出來。還要待我思索怎麼做,
現在再寫下去就可以看日出了,所以先暫停。日後也希望把 facebooker plugin
拿掉,改成類似這邊 ffbapi adapter 的做法。

光以上,沒幾行程式,就費去我大半天的時間。我在想是我變笨了呢,
還是這本來就這麼複雜?早上寫到卡很久,只好再拿出紙筆出來鬼畫了一下。
重新調整後就變成這樣的結構了。

接下來就可以真的處理訂閱的部份,透過 photoship.
這邊我原本一直寫成用另外一個 repo, 所以才會有 cache (3) 那篇的東西。
結果用了一堆方法,怎麼做都不太理想。因為 DM 的 repo 似乎不能分 property.
也就是說,新出來的 friends_photos 需要多一個欄位,紀錄 watcher 是誰?
而這會使得 :default repo 也需要一個 watcher 欄位...

因為 DM 跨 repo 只能是 mapping 方式不同,而不能是 property 也有異。

repository(:friends_photos){ property :watcher, User }

這樣是不行的,會造成 :default 也有效果,我也不想多開新欄位,
patch DM 又太花時間了,只好先放棄這個。改成繼承,失敗得更慘,
因為連 auto_migrate! 都失效了,storage 只會出現一個。

module? 那又要處理 property holder, 有點煩。
想到 dm-is-remixable, 可以做些程式碼重複利用。
不過這個做法好像是拿來取代 rails 的 polymorphic association,
會產生新的 class 出來,看起來是對不太起來,要改也一樣是麻煩。

又想了很久很久,也試了很久很久,忽然間恍然。其實根本不用這麼麻煩,
所以資料可以都用同一份,這樣連 expire 的問題都不用考慮了。
cache 另一個大麻煩就是 expire 的機制啊!

而 comments_count 可不可以照用?說不定可以,把 counts 偷存在
relationship 中。搞不好就真的做得像 ada 說的一天存一筆 count,
有 post comment 時才更新資料,就可以抓出七天的資料再 sum 起來。
這樣甚至可以省去全資料掃描的動作,只是又有更多東西需要處理...
像是 compact 之類的動作。這,晚點再說吧... cache 做下去真的做不完。

不過說到這,忽然間就發覺 google analytics 超難做啊!
能在 google 裡寫這些東西的話應該會滿有趣的吧..?

總之,前面試了那麼多種方法,用 has n, :through 是會比較慢沒錯,
但省去很多複雜度,資料庫效能我不熟,但至少程式這樣寫是真的漂亮得多。
寫程式真的有很多技巧性的東西,看你有沒有想到而已。想到就能事半功倍,
否則就要用各種怪招,陷在泥沼、焦油坑裡面掙扎罷了...

然後 there's always a deadline, 也不能無止盡思索,
所以就變成邊寫邊想,design + programming + refactoring 同時進行。

簡稱:OO D P R XD

前面搞得很複雜,想到這招後就很簡單了:
module Cron
module Photo
module_function
def photoship photo
photo.user.friends.each{ |friend|
Cache::Photoship.create( :photo_id => photo.id,
:user_id => friend.id,
:created_at => photo.created_at ).compact!
}
end
end
end

多一個 created_at 紀錄 photo 的 created_at, 僅紀錄最新幾筆,
比較舊的資料就全部刪掉,所以最後接個 compact! 實作如下:
def compact! n = 3
user.photoships( :order => [:created_at],
:limit => 1000,
:offset => n ).destroy!
end

預設只留三張。那個 limit 好像不能省略,省略會噴 SQL error @@
那就隨便打個數字上去。想想也不敢打個 100000000000 上去,
要是真有那麼多那也太浪費時間了,一次砍 1000 很快也可以砍完。

接下來就把其中的一些東西移植到 AR 上就可以正式運作了。
不過剛才試跑了一下,發覺可能還需要調整,因為資料量超大! @@
現在才一點測試資料而已,cache_friendships 就衝到兩萬多筆 @@
稍微估計一下,最大可能會到十六萬左右,這不知道撐不撐得住...

再改回雙向紀錄其實也很快就是,就看哪種比較節省系統資源。

然後 photoships 的 compact 滿有用的,沒跑之前約衝到一兩萬筆,
每人只留三筆後就只剩三百多。想想,這數量可是會遠遠超過相片量!
假設每個人有 100 張,共有 100 人,總數就是一萬張。
此時每個人假設有 10 個朋友,每個人每個朋友都會保留三張,
100 * 10 * 3 => 900
一百個朋友的話就是 9000 張了。這樣要突破一百萬筆資料,真的會很快...

啊如果我要處理這麼多東西,還要搞 UI 和 javascript, 實在是很煩 :s

為什麼寫這麼久!?因為事情真的是好多啊...
剛剛稍微翻了一下程式碼,也想起好多東西都是之前花很多心思弄的。
不過那些東西真的是寫好之後就可以忘記,因為後面用起來都很順手。
例如 @visitor 就一定是現在這個拜訪者,而 visitor_open 就一定有權限管控。
each_photos 就可以 travel 剛剛上傳的所有 photos,
massive_update 就可以邊檢查權限邊更新所有 photos.

一層一層這樣包上來,隨時在各個層次穿梭著。

All texts are licensed under CC Attribution 3.0