λ

(conj clojurians me)

我的疑问


面向对象编程和函数式编程的最大不同点在什么地方?

  • 数据从何而来?面向对象编程中的数据都是对象本身产生的,也就是说对象的基础建立在它本身的属性上,没有属性,那么这个对象什么都不能做。函数式(闭包)的过程数据来自于外部,也就是说闭包本身是不维护数据的。这样的好处是只管逻辑,而不用维护数据本身复杂的状态。

  • 数据的状态如何?面向对象编程中数据(也就是属性)是可以改变的,而函数式中数据是不可以改变的。

  • 没有属性的对象,还是面向对象嘛?我认为controller, service, DAO(repository)其实都是没有数据的对象!也就是说这些分层结构其实都是函数式编程可以应用的地方。有人会说奇怪了,controller中明明有service属性,service中明明有DAO属性啊,怎么能说没有数据呢?其实,这个只是调用链(我喜欢把它们看作是filter),真正的数据(大概被称为model)是被一层层传递下去的。可能又有人会反驳,函数式中最大的特点就是数据不可变,这些真正的数据(model)在传递过程中其实是会被改变的,所以怎么能说这些地方可以应用函数式编程?我认为,这些数据在各个层上应该是不同类的。展现给view的,和存储到database中的model是很难相同的,所以也就存在一种模型之间转化的可能,一个模型变成另一个新的模型,模型本身是不会变的。

  • 没有方法的值对象呢?就是数据吧。

AOP和函数式编程有没有关系?


AOP是什么?

AOP是面向切面编程。我们平时编写web程序的时候,通常都会使用controller->service->dao这样的层次结构的调用链。事实上,有些逻辑不是纵向延伸的,对于单个的层级,如service,一个典型的应用就是Log处理:我们需要对service中涉及写入数据库的操作进行记录,这样的逻辑对于service上的所有需要log记录的方法而言是通用的。所以没有必要在各个不同的services上手工记录log,我们只需要将这部分log的逻辑抽出来作为独立的方法,然后很形象地表述成在services上的方法打上一个个洞,将这部分独立的方法像插槽(阀门)一样插入这些洞里,流过services上这些被记录的方法上的数据及其本身就会被完整的记录下来。

AOP的概念也很有趣。事实上,AOP中的Joinpoint,Pointcut,Advice可以分别类比为钩子,晾衣杆和晾衣服这个动作。Joinpoint就是要拿来鼓捣的方法,Pointcut则是将这些方法串起来,Advice是统一处理这些方法的逻辑操作,同时也包括了它自身的执行时机,是在Pointcut之前、之后或是其中,当然更有甚者,是在方法返回之后,还是抛出异常之后呢?

那么接下来,我们来看看AOP和函数式编程到底有没有关系。第一个方面,AOP其实是间接地拿函数作为自己的参数了。举个例子,拦截controller的方法:

1
2
3
4
5
6
7
@AfterReturning(value = "execution(* controller.*.*(..)) && args(customer)",
returning = "result")
public void aMethod(Customer customer, String result) {
System.out.println("before");
System.out.println(result);
System.out.println("after");
}

其实这样的方式——既拿到了输入参数,又拿到了输出参数,就等于已经拿到了整个方法,何况还有牛掰的@Around,直接拿人家的方法到自己的方法体里执行。而函数式第一要点就是函数是一等公民,函数可以作为参数传递。所以说从获取参数这个层面说,两者实在太相像了。

第二个方面,抽取共有逻辑。函数式中有惰性求值,假设我们在函数式中预留一个Function作为钩子,任何想使用这部分函数逻辑的在需要的时候,通过某种机制传递真正的Function到我们的预留参数中,是不是也能实现抽取共有逻辑呢?还有,我们之所以有很多services,是因为model(domain)存在差异,假设函数式中没有OO的概念,model似乎就趋同了,那么或许我们根本不需要services。所以函数式是可以抽取共有逻辑的,或者说这部分逻辑本来就不应该分散到各个services中。

结论处,我大胆地猜测:AOP其实就是OO被掣肘之后,利用函数式缝补自身的妥协方案。AOP本来就是Functional programming.

Functional Programming的要点


  • 声明式编程
  • 不变量
  • 无副作用的函数
  • 不会依附于任何类或者对象,这点“functional programming for java developer”中有清楚描述。在java中写的大部分函数式代码都是静态的,但逻辑上,它不属于这个类。

Mysql 5.5 CharacterSet Configuration

Client Configuration

  • #1 No need to restart server for setting client

When

1
2
[client]
default-character-set = utf8

Then

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql  Ver 14.14 Distrib 5.5.38, for debian-linux-gnu (x86_64) using readline 6.2

Connection id: 40
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
  • #2 It will change character_set_client & character_set_connection & character_set_results without client’s setting.

When

1
2
[client]
#default-character-set = utf8

Then

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Connection id:		37
Current database: mall
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: latin1
Conn. characterset: latin1
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 14 min 4 sec

And Then

1
2
3
4
5
6
7
8
9
10
11
12
13
For a special DB.
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

Server Configuration

  • #1 Restart mysql server without character-set-server=utf8

When

1
2
[mysqld]
#character-set-server=utf8

Then

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql  Ver 14.14 Distrib 5.5.38, for debian-linux-gnu (x86_64) using readline 6.2

Connection id: 42
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 8 min 47 sec
  • #2 Create a new database newa without character-set-server=utf8

When

1
2
[mysqld]
# character-set-server=utf8

Then

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Connection id:		36
Current database: newa
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 12 sec
  • #3 Restart server with character-set-server=utf8

When

1
2
[mysqld]
character-set-server=utf8

Then

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Connection id:		38
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 23 min 46 sec

But For newa DB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CConnection id:		38
Current database: newa
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.38-0ubuntu0.12.04.1 (Ubuntu)
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: ***latin1***
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 22 min 36 sec

So That Means

The character set used by the default database. The server sets this variable whenever the default database changes. If there is no default database, the variable has the same value as character_set_server.

conclusion

  • For client, connection, results, you should add
    [client] default-character-set = utf8

  • For server and DB, you should add
    [mysqld] character-set-server=utf8

  • You should drop original DB when created in error character set, just like newa DB

Sublime Text3 Plugins

jshint for sublime installation

  1. brew install nodejs
  2. npm install -g jshint
  3. open sublime & package control install jshint
  4. that’s ok

install SublimeOnSaveBuild

  1. open sublime & package control install SublimeOnSaveBuild
  2. that will build jshint once save

expand region

  1. open sublime & package control install Expand_region
  2. change the default-keymap
    { “keys”: [“super+w”], “command”: “expand_region”}

jshint gutter

  1. open sublime & package control install jshint gutter
  2. ctrl+shit+j to lint code!

PackageResourceViewer

  1. install PackageResourceViewer by package control
  2. ctrl+shift+p to use ‘open resource’
  3. find tm.theme, then add something end
1
2
3
4
5
6
7
8
9
10
11
<dict>
<key>name</key>
<string>Bracket Curly</string>
<key>scope</key>
<string>brackethighlighter.curly</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CC99CC</string>
</dict>
</dict>

BracketHighter

  1. must have packageresourceviewer at first
  2. clear the annotation of color, and then save

Trailing Spaces

  1. install Trailing Spaces by package control
  2. configure keymap
1
2
3
4
5
6
7
8
9
10
11
12
{
"command": "toggle_trailing_spaces",
"keys": [
"ctrl+shift+d"
]
},
{
"command": "delete_trailing_spaces",
"keys": [
"ctrl+shift+t"
]
}
  1. configure trailing_spaces.sublime-settings
1
2
3
4
5
## color: invaild, comment, error
{
"trailing_spaces_highlight_color": "comment",
"trailing_spaces_trim_on_save": true
}

Centurion theme

  1. install theme Centurion first,
  2. open Preferences->Settings - User,
  3. insert {"theme": "Centurion.sublime-theme"},
  4. every time, subl3 use .sublime-theme as suffix.

install SyncedSideBar (keep sync between sidebar and opening file)

  1. install SyncedSideBar,
  2. open Preference->Key Bindings - User,
  3. configure keymap
1
2
3
4
{
"command": "reveal_in_side_bar",
"keys": ["alt+f1"]
}

Rake Version Conflicts

1
bundle exec rake CMD.

Invalid byte sequence in US-ASCII

1
2
3
4
5
6
7
8
*Excpetion*
bundle exec rake generate
(in /Users/qianyan/Dropbox/octopress)
Generating Site with Jekyll
identical source/stylesheets/screen.css
Configuration from /Users/qianyan/Dropbox/octopress/_config.yml
Building site: source -> public
YAML Exception reading 2013-12-10-hello-world.markdown: invalid byte sequence in US-ASCII

Resolve this problem

1
2
3
4
> vim ~/.zshrc
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
> source ~/.zshrc

  1. Find your theme file in ~/.oh-my-zsh/themes/, then edit it;

  2. Add local svn_info='$(svn_prompt_info)';

  3. Append %{$reset_color%}${svn_info} to Prompt variable;

  4. Add followings to END-OF-FILE.

1
2
3
4
ZSH_THEME_SVN_PROMPT_PREFIX="%{$fg_bold[blue]%}svn:("
ZSH_THEME_SVN_PROMPT_SUFFIX="%{$fg_bold[blue]%})"
ZSH_THEME_SVN_PROMPT_DIRTY="%{$fg[red]%} ✘ %{$reset_color%}"
ZSH_THEME_SVN_PROMPT_CLEAN="%{$FG[040]%} ✔"

And you can refer the theme (awesomepanda)

修改Vagrantfile


1
2
3
4
5
6
# 把客户机器(ubuntu)的port 3306 映射到宿主机器上的port 3306
config.vm.network :forwarded_port, guest: 3306, host: 3306

# 执行安装程序
config.vm.provision :shell :path => "install_mysql.sh"

mysql安装程序


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
echo "Setup mysql-server-5.5 if not exists.."
sudo debconf-set-selections <<< 'mysql-server-5.5
mysql-server/root_password password root'
sudo debconf-set-selections <<< 'mysql-server-5.5
mysql-server/root_password_again password root'
sudo apt-get update
sudo apt-get -y install mysql-server-5.5

if [ ! -f /var/log/databasesetup ];
then
echo "CREATE USER 'codeeker' IDENTIFIED BY 'codeeker'" | mysql -uroot -proot
echo "CREATE DATABASE mall" | mysql -uroot -proot
echo "GRANT ALL ON mall.* TO 'codeeker'@'%'" | mysql -uroot -proot
echo "flush privileges" | mysql -uroot -proot

touch /var/log/databasesetup #为了不重复执行创建用户的操作

if [ -f /vagrant/data/initial.sql ];
then
mysql -uroot -proot codeeker < /vagrant/data/initial.sql
fi
fi

陷阱

错误一

  • 报错误Lost connection to MySQL server at 'reading initial communication packet', system error: 0
  • 原因是 /etc/mysql/my.cnf中有bind-address = 127.0.0.1,会拒绝非localhost的访问,包括vagrant映射port到的宿主主机上
  • 解决的方法是修改bind-address = 0.0.0.0,表示接受本网络中所有的ip登录

错误二

echo "CREATE USER 'codeeker' IDENTIFIED BY 'codeeker'" | mysql -uroot -proot

如果写成了

echo "CREATE USER 'codeeker'@'localhost' IDENTIFIED BY 'codeeker'" | mysql -uroot -proot

那么在宿主的机器上,会报access deny错误。

  • 原因是这样创建的用户,只能在localhost上登录
  • 解决的方法是去掉@'localhost'

灯火比白昼柔和

我的影子比夜长

也比夜凉

Shell Skills

sudo !!

以root的身份执行上一条命令 。
场景举例:比如Ubuntu里用apt-get安装软件包的时候是需要root身份的,我们经常会忘记在apt-get前加sudo。每次不得不加上sudo再重新键入这行命令,这时可以很方便的用sudo !!完事。
(在shell下,有时候你会输入很长的命令,你可以使用!xxx来重复最近的一次命令,比如,你以前输入过,vi /where/the/file/is, 下次你可以使用 !vi 重得上次最近一次的vi命令。)

cd -

回到上一次的目录 。
场景举例:当前目录为/home/a,用cd ../b切换到/home/b。这时可以通过反复执行cd -命令在/home/a和/home/b之间来回方便的切换。
(cd ~ 是回到自己的Home目录,cd ~username,是进入某个用户的Home目录)

‘ALT+.’ or ‘ .’

热建alt+. 或 esc+. 可以把上次命令行的参数重复出来,有点像!$,但是它只会在当前行出现,而不会想!$在下一行将命令展开以补全。

^old^new

替换前一条命令里的部分字符串。
场景:echo "wanderful",其实是想输出echo "wonderful"。只需要^a^o就行了,对很长的命令的错误拼写有很大的帮助。(陈皓注:也可以使用 !!:gs/old/new)
eg:
> echo "wanderful"
> ^a^o
> echo "wonderful" (*auto popup*)

w !sudo tee %

在vi中保存一个只有root可以写的文件

> file.txt

创建一个空文件,比touch短。

ps aux | sort -nk +4 | tail

列出头十个最耗内存的进程

ctrl-x e

快速启动你的默认编辑器(由变量$EDITOR设置)。

python -m SimpleHTTPServer

一句话实现一个HTTP服务,把当前目录设为HTTP服务目录,可以通过http://localhost:8000访问 这也许是这个星球上最简单的HTTP服务器的实现了。

man ascii

显示ascii码表。

ssh user@server bash < /path/to/local/script.sh

在远程机器上运行一段脚本。这条命令最大的好处就是不用把脚本拷到远程机器上。

du -s * | sort -n | tail

列出当前目录里最大的10个文件。

###Bash - login-sh & interactive-sh

login shell

  • what is login shell?
    1
    2
    echo $0
    > -bash (prefix should be '-', this mean bash is login shell)

interactive shell

  • what is interactive shell?
    1
    2
    echo $-
    > 569JNRTXZghilms (you can see 'i', that means it is interactive shell)

the defference between the two shells?

the order of loading profile

  • login shell
    1
    2
    3
    /etc/profile
    ~/.bash_profile
    ~/.profile
  • interactive shell
    1
    2
    /etc/bash.bashrc
    ~/.bashrc

why can I load .bashrc on Ubuntu linux?

because in ~/.profile also source the .bashrc

what kind of shell is neither login-sh nor interactive-sh

shell run in the command scripts.

Basic Knowledeg

1. prefix notation

1
2
3
4
(- 3 2 1) ; => 0
(+ 1 2 3) ; => 6
(< 1 2 3) ; => true
(< 1 4 2) ; => false

2. data type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(class 1) ;=> java.lang.Long
(class 1.0) ;=> java.lang.Double
(class true) ;=> java.lang.Boolean
(class "str") ;=> java.lang.String

(class (byte 1)) ;=> java.lang.Byte
(class (short 1)) ;=> java.lang.Short
(class (int 1)) ;=> java.lang.Integer
(class (float 1.0)) ;=> java.lang.Float
(class (char 'a')) or (class \a) ;=> java.lang.Character

(class (/ 1 3)) ;=> clojure.lang.Ratio, support lazy evaluating.

(class 36786883868216818816N) ;=> clojure.lang.BigInt
(class 3.14159265358M) ;=> java.math.BigDecimal

3. expression

  • if [else]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (if (< 1 2)
    (println "it is true")
    (println "it is false")
    ) ;=> it is true

    (if ""
    (prn "it is true")) ;=> it is true

    (if 0
    (prn "it is true")) ;=> it is true

    (if nil
    (prn "it is true")) ;=> nil!!
  • or/and
    1
    2
    (prn (or true false)) ;=> true
    (prn (and true false)) ;=> false

4. data structures

  • list
    1
    2
    3
    (list 1 2 3)
    `(1 2 3)
    ;=> (1 2 3)
  • vector
    1
    [1 2 3] ;=> [1 2 3]
  • set
    1
    #{1 2 3} ;=> #{1 2 3}
  • map
    1
    2
    3
    {:one 1,
    :two 2,
    :three 3} ;=> {:one 1, :three 3, :two 2}

5. operation on data structures

  • op list (seq access)
    1
    2
    3
    4
    5
    (def list0 `(1 2 3))
    (first list0) ;=> 1
    (rest list0) ;=> (2 3)
    (last list0) ;=> 3
    (cons 0 list0) ;=> (0 1 2 3)
  • op vector (rand access)
    1
    2
    3
    4
    (def vec0 [4 5 6])
    (nth vec0 2) ;=> 6
    (vec0 2) ;=> 6, with index.
    (concat [1 2 3] vec0) ;=> (1 2 3 4 5 6), it called sequence.
  • op set
    1
    2
    3
    (def set0 #{5 7 2 6})
    (count set0) ;=> 4
    (set0 2) ;=> 2
  • op map
    1
    2
    3
    4
    5
    6
    (def map0 {:one 1, :two 2, :three 3})
    (map0 :one) ;=> 1
    (:one map0) ;=> 1
    (merge {:four 4} map0) ;=> {:two 2, :three 3, :one 1, :four 4}

    (def map1 (sorted-map 2 :two 1 :one)) ;=> {1 :one, 2 :two}
0%