Alex Liang

Archetecture the Lost Years by Uncle Bob演講筆記

最近看了Uncle Bob在Ruby Midwest 2011的演講(影片連結)介紹軟體架構。

Archetecture is about intent

一開始Uncle Bob列出幾種建築物的結構圖,藉此比喻好的架構設計能讓工程師迅速了解系統
從這裡再帶出web framework常採用的MVC架構
為何會有MVC的出現? 為了讓系統耦合度降低 讓前端的設計不需要跟後端的資料庫或商業邏輯綁在一起

演講從一個user case講起,再畫一個UML圖解釋架構。
他使用類似MVC架構的系統(interactor, entity, boundary)來處理這個問題
例如: interactor負責application特有的商業邏輯,並且和entity有連結的關係,可以視為controller
entity則是處理資料庫存取,屬於一般application共有的行為
boundary把interactor產生的資訊秀出來給使用者,整體架構如下圖所示:
螢幕快照 2016-04-01 下午4.44.26.png
Uncle Bob解釋這種設計能將商業邏輯和使用者介面切開,二者之間少了相依性
而右半邊的interactor和entity可封裝成gem或dll(看是哪種application)
最左邊的delivery machanism負責將user input分配給boundary,可封裝成plug-in的型態,方便測試

What about MVC?

講到MVC這章,先從發明人Trygve Reenskaug開始介紹
延申到web application時會出現view和controller相依model的現象,如下圖
螢幕快照 2016-04-04 下午2.27.14.png
從測試的角度來看,view只要把資訊編排顯示正確即可,不需要關心後端的資料如何產生
對於商業邏輯的正確才是每次測試的重點,這點他比較偏好Model-View-Presenter
螢幕快照 2016-04-04 下午3.06.06.png

接下來Uncle Bob問觀眾做一次測試要多久?測了幾項?

4分半測1000多項 –> That’s good
1小時半 –> That’s bad >”<

對工程師來說,測試如果花太久的時間,之後每次修改都會猶豫要不要測試。
這也增加專案爆炸的機率…

Good Architeture

Uncle Bob最後提到早期一個wiki-like project。
從一開始他們就決定晚一點連結資料庫,先把application實作完
為了滅少測試時間,把wiki page存在memory中,雖然不能存檔,但至少能測試整個專案
後來他的同事實作FileSystemPage測試persistence,架構如下
螢幕快照 2016-04-04 下午3.30.17.png
而這時專案還沒有真正的database

A good architecture allows major decisions to be deferred
A good architecture maximizes the number of decisions not made

到最後客戶要求需要database,而他們只需要一天就把專案完成了

好的架構可推遲重大的決定;好的架構能滅少做決定的次數。

[前端筆記] CSS3 Cross Country筆記

把Code School CSS3課程做個筆記

Inheritance & Specificity

CSS3對selector和class有優先權的設定
有個數列能做參考:

, , ,
由左至右為權限高到低,舉例來說

1
2
3
4
<section id="content">
<p class="product">Coffee brewer</p>
<p>It's the best way to enjoy coffee</p>
</section>

1
2
3
4
5
6
7
8
9
#content p {		# specificity: 0,1,0,1
color: #000;
}
.product { # specificity: 0,0,1,0 優先權較低,不會生效
color: #555;
}
#content .product { # specificity: 0,1,1,0 加上ID selector才會生效
color: #555;
}

The Box Model

當我們需要計算某個樣式的寬度時,需套入以下公式:
total calculated box width = content width + padding width + border width
例如:

1
2
3
4
5
6
.form {
border: 5px solid #fff;
padding-left: 10px;
padding-right: 5px;
width: 120px;
}

此樣式總寬度為: 120(content)+15(padding)+10(border)=145px

Positioning

CSS的樣式位置預設是static,總共有4種設定:static/relative/absolute/fixed
除了static之外,其它3種設定可分別調整元素上、下、左、右位置,例如:

1
2
3
<article>
<h2>Alex's Playground<sup>2</sup></h2>
</article>

1
2
3
4
5
6
sup {
font-size: 60%;
vertical-align: baseline;
position: relative;
top: -0.5em;
}

螢幕快照 2016-04-01 下午2.17.56.png

參考來源:
Positioning

[Rails] paperclip上傳檔案及圖片

如果網站需要上傳檔案或圖片的功能,除了carrierwave之外,也可以使用paperclip實現

以下介紹這個好用的gem

環境要求

要使用paperclip,ruby的版本必須是2.0以上,rails則是3.2之後

imagemagick也得先安裝,在OS X下,使用Homebrew安裝

1
brew install imagemagick

安裝

Gemfile
1
gem "paperclip", "~> 4.3"
1
> bundle install

Model

設定model,假如有一個Pic model負責管理圖片

pic.rb
1
2
3
4
class Pic < ActiveRecord::Base
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end

Migration

1
> rails generate paperclip pic avatar

Controller

pics_controller.rb
1
2
3
4
5
6
7
8
9
def create
@pic = Pic.create(pic_params)
end

private

def pic_params
params.require(:pic).permit(:avatar)
end

View

1
2
3
<%= image_tag @pic.avatar.url %>
<%= image_tag @pic.avatar.url(:medium) %>
<%= image_tag @pic.avatar.url(:thumb) %>

參考來源:
paperclip github repo

[Rails] HAML介紹

這二天接觸到haml這個輕量級語言,在嘗試後發覺真的是很方便的語言,可以用更優雅的方式撰寫前端的template

以下做個整理

首先得安裝gem

1
2
3
gem "haml"

> bundle install

HAML必須將.erb檔案改為.haml,如app/views/docs/index.html.erb改為app/views/docs/index.html.haml

基本的轉換規則如下:

1. html的tag改用%代替,例如<header>改為%header,不需要close tage
2. class attribute改用.,例如<div class="nav">改為.nav
3. id attribute改用#,例如<div class="banner" id="message">改為.banner#message
4. 遇到<%= ...>的代碼改用=,例如<= f.input>改為= f.input

舉例:

show.html.erb
1
2
3
4
5
6
7
8
9
10
11
<div class="wrapper_with_padding>
<div id="doc_show">
<h1><%= @doc.title %></h1>
<p><%= simple_format(@doc.content) %>

<div class="buttons">
<%= link_to "Fix Doc", edit_doc_path(@doc), class: "button" %>
<%= link_to "Delete Doc", doc_path(@doc), method: :delete, data: {confirm: "Are you sure?"}, class: "button" %>
</div>
</div>
</div>
show.html.haml
1
2
3
4
5
6
7
8
.wrapper_with_padding
#doc_show
%h1= @doc.title
%p= simple_format(@doc.content)

.buttons
= link_to "Fix Doc", edit_doc_path(@doc), class: "button"
= link_to "Delete It", doc_path(@doc), method: :delete, data: {confirm: "Are you sure?"}, class: "button"

參考資料:
haml官網教材
haml refrence

[前端筆記] html/CSS觀念記錄

上完code school的javascript課後,回頭再複習前端的基礎-html和CSS
對一個網頁來說,html控制文章架構、CSS則決定樣式
以下記錄一些觀念:

HTML

1. ul是指unordered list,顯示bullet項目
2. ol是指ordered list,顯示編號項目
3. 在head中加入CSS的檔案,需使用<link style type="text/css" rel="stylesheet" href="css file"> 
    4. 續上,link和img都是empty tag。它們不用加上closing tag 

The box model

html的文字採用box model,包含4個項目:

  1. content area內文
2. padding 內文四個方向的留白
3. border 內文四個方向的框線
4. margin 是border外的留白區域

圖示如下:
box-model

當我們需要調整段落間的距離或文字間留白,可調整margin或padding;如果要加框線,則使用border

CSS Selector

如果我們要微調某部分的html style,可使用html class和CSS selector
以下例子是將ul內的項目左邊padding 15pixel:

1
2
3
<ul class="nav">
...
</ul>
1
2
3
.nav {
padding-left: 15px
}

要注意的是CSS的selector與其它樣式的順序會影響結果,以下這個例子會把nav class設定的padding-left覆寫:

1
2
3
4
5
6
.nav {
padding-left: 15px
}
ul {
padding-left: 10px
}

[Javascript筆記] Object介紹

Javascript的object”類似” C++或Java的class (說類似是因為它多了動態語言的特性,以及存取方式)

object擁有property和method(也可視為property)

例如一台車,它有馬力、重量以及啟動、煞車功能。 我們可以用一個object表示:

car.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var car = {			// object使用{}宣告
horsePower: 200,
weight: 4000,
start: function() {
alert("Start engine!");
},

break: function() {
alert("Break!");
}
};

console.log(car.horsePower); // 印出200
console.log(car["weight"]; // 也可以使用[]存取property

Object也可以動態增加property:

car.js
1
car.brand = "Toyota";

刪除property:

car.js
1
delete car.brand;

Object也可以包含其它的object

vehicle.js
1
2
3
4
var vehicle = {
Car: {horsePower: 300, weight: 2000},
Boat: {weight: 400000, height: 300000}
};

增加一method可動態新增object

vehicle.js
1
2
3
4
5
6
7
8
9
var vehicle = {
Car: {horsePower: 300, weight: 2000},
Boat: {horsePower: 400000, weight: 300000},
addVehicle: function(name, horsePower, weight) {
this[name] = {horsePower: horsePower, weight: weight}; // 使用this表示vehicle本體
}
};

vehicle.addVehicle("Plane", 600000, 8900000);

假如要計算vehicle內object的個數,需要用for-in loop:

vehicle.js
1
2
3
for (key in vehicle) {		// key會存取vehicle內每個property
console.log(key); // 印出Car, Boat, addVehicle, Plane
}

參考資料:
object介紹

[Ruby筆記] .each v.s. for

練習Learn Ruby the Hardway時,習題32講到迴圈和陣列。 其中存取陣列時有二種不同的方式:.each和for

這二種方式看起來差不多,但對於程式碼執行結果會讓人有”驚喜”的感覺

二者的差異在於scope,對C/C++或Java等靜態語言來說,在{}內或function內的變數只在local有效

而javascript或ruby對變數的scope則略有不同

如以下的程式碼,for不會建立新的scope;而each會建立新的scope

1
2
3
4
5
6
7
8
9
10
11
12
13
count = [1, 2, 3, 4, 5]
for number in count
z = number
end

puts z # 5
puts number # 5

count.each do |y|
a = y
end
puts a # undefined local variable
puts y # undefined local variable

我們在使用each時得小心這個特性,以免造成莫名其妙的bug。

參考資料:
stack overflow討論

[Javascript筆記] Hoisting

在Javascript中對於宣告(declaration)會移到作用域的最上方,此預設行為稱為Hoisting。

以下的範例會印出10

1
2
3
x = 10;
var x;
console.log(x);

實際上javascript interpreter會將x的宣告移到上方,也就是:

1
2
3
var x = undefined;
x = 10;
console.log(x);

hositing也會影響function expression的執行,例如:

1
2
3
4
5
6
7
8
9
10
11
function hoistingTest() {
foo(); // 錯誤
bar();
var foo = function () {
alert("foo");
};

function bar() {
alert("bar");
}
}

這段程式碼對javascript來說是長這樣:

1
2
3
4
5
6
7
8
function hoistingTest() {
var foo = undefined;
foo(); // 此時foo為一undefined的變數
foo = function () {
alert("foo");
}
// ...略
}

Javascript雖然語法上是c-like,但在作用域(scope)的觀念有差別,這也會影響程式執行結果。

參考資料:
Javascript Scoping and Hoisting
Hoisting基本解說

[Javascript筆記] Anonymous Function

對一位C/C++ programmer來說,javascript的anonymous function(匿名者函式)是容易讓人困惑的存在。
如何使用沒有identifier的function? 有什麼好處? 在這裡做個筆記。

javascript提供3種宣告function的作法

Function Declarations

一般function的作法,需要提供function name,範例如下

1
2
3
4
5
function multiply(a, b) {
return a * b;
}

console.log(multiply(3, 4)); // Print 3 * 4

The Function() Constructor

類似C++的建構者函式 (constructor),只不過是用在function上

1
2
var mulitplyFunc = new Function("a", "b", "return a * b");
var x = mulitplyFunc(3, 4);

一般來說不建議用此方式宣告函式

Function Expressions

也就是這篇的主角,function expression不需要function name,可視為variable

1
2
var mulitplyFunc = function (a, b) { return a * b; };
var x = multiplyFunc(3, 4); // Calculate 3 * 4

使用anonymous function的好處

  1. 可用來實做Closure,實現design pattern的工廠方法
  2. 簡化程式碼,提高易讀性
    之前要用C++實作工廠方法時,需要dynamic binding的技術,確實要花點心思
    下一篇討論closure

參考來源:
Javascript function基本教學
關於lambda觀念的說明
比較ruby和js的anonymous function
Javascript function declarations vs function operators

[Rails] 使用figaro管理密鑰

figaro是一個管理機密資訊或密碼的gem,以下介紹如何同步資訊到heroku上

安裝figaro

Gemfile
1
gem "figaro"
1
$ bundle install
1
$ figaro install

管理機密資訊

假如有一組key不希望公開至github,則我們先把資訊存在yml檔,再使用ENV存取

config/application.yml
1
2
3
product_app_id: "2924"
product_key: "7ad1a978f7dd7f9a1117"
product_secret: "11dcb896a0ffb85d373"

在initializer中存取資訊
config/initializers/pusher.rb
1
2
3
Product.app_id = ENV["product_app_id"]
Product.key = ENV["product_key"]
Product.secret = ENV["product_secret"]

佈署至HEROKU

1
$ figaro heroku:set -e production

查循目前設定

1
$ heroku:config

參考來源:
figaro github