<![CDATA[CleverDeng时光 - 记录、分享...]]>http://blog.mrdtime.com/enhttp://www.mrdtime.comhourly1Copyright:© CleverDeng's timehttp://blog.mrdtime.com/920-您是否是靠谱的程序员?.aspx<![CDATA[您是否是靠谱的程序员?]]>CleverDengSat, 09 Jul 2011 12:08:20 GMThttp://blog.mrdtime.com/920-您是否是靠谱的程序员?.aspx 然,扪心自问,反省,本身的价值有多大?是否是真正意义上的靠谱程序员?相信对于这个命题,也许太过广泛,可以多维度的大谈特谈,比如可以从代码质量、解决问题能力、解决问题方案等等来个几十大条。可我却想从解决问题的方案层面上谈谈,算抛砖引玉罢。

一个简单的问题:求2个集合的交集。(集合的存储形式可以是记录表、数组等容器就行)

input_1:1,5,20,11,10,170,50,200,100
input_2:100,50,30,15,150,80,200,48
out:100,50,200
对于上述的问题,按照本人从高中开始程序设计的路线而言,依稀记得用过过以下解决问题的方案:

1> 一种非常直白的方法,对这2个集合遍历一次,就能找到交集数据。代码如下(Python):

input_1 = [1,5,20,11,10,170,50,200,100]
input_2 = [100,50,30,15,150,80,200,48]

def one():
    out = []
    for input_1_item in input_1:
        for input_2_item in input_2:
            if input_1_item == input_2_item:
                out.append(input_1_item)
  
    return out

if __name__ == "__main__":
    print one() 

2> 后来,听说hashtable,因此也有过这种写法,利用hashtable的特性。代码如下(Python):

def two():
    out = {}
    for input_1_item in input_1:
        out[str(input_1_item)] = out.get(str(input_1_item), 0) + 1

    for input_2_item in input_2:
        out[str(input_2_item)] = out.get(str(input_2_item), 0) + 1

    return [int(k) for k,v in out.items() if v > 1]

if __name__ == "__main__":
    print two() 

3> 后来的后来,接触算法分析后,也有过这种写法,先排序,使之成为有规划的数据。代码如下(Python):

def three():
    out = []
    input_1.sort()
    input_2.sort()

    point_1 = 0
    point_2 = 0

    while point_1 < len(input_1) and point_2 < len(input_2):               
        if input_1[point_1] == input_2[point_2]:
            out.append(input_1[point_1])
            point_1 += 1
            point_2 += 1
        elif input_1[point_1] < input_2[point_2]:
            point_1 += 1
        else:
            point_2 += 1

    return out

if __name__ == "__main__":
    print three()

4> N次后来,Python内建的集合运算很给力,简单的使用运算符就可以解决此问题,因此也有过这种写法,代码如下(Python):

def four():
    return list(set(input_1) &  set(input_2))

if __name__ == "__main__":
    print four() 
对于上述这个问题,我相信您可能在使用上述的某种解决方案,既然出现了多种解决方案,您能否快速明了的说出各种方案的优缺点且适应某种场合呢?我相信作为靠谱的程序员一点压力都没有,简直是玩儿似的。那么您是否是靠谱的程序员呢?]]>
然,扪心自问,反省,本身的价值有多大?是否是真正意义上的靠谱程序员?相信对于这个命题,也许太过广泛,可以多维度的大谈特谈,比如可以从代码质量、解决问题能力、解决问题方案等等来个几十大条。可我却想从解决问题的方案层面上谈谈,算抛砖引玉罢。

一个简单的问题:求2个集合的交集。(集合的存储形式可以是记录表、数组等容器就行)

input_1:1,5,20,11,10,170,50,200,100
input_2:100,50,30,15,150,80,200,48
out:100,50,200
对于上述的问题,按照本人从高中开始程序设计的路线而言,依稀记得用过过以下解决问题的方案:

1> 一种非常直白的方法,对这2个集合遍历一次,就能找到交集数据。代码如下(Python):

input_1 = [1,5,20,11,10,170,50,200,100]
input_2 = [100,50,30,15,150,80,200,48]

def one():
    out = []
    for input_1_item in input_1:
        for input_2_item in input_2:
            if input_1_item == input_2_item:
                out.append(input_1_item)
  
    return out

if __name__ == "__main__":
    print one() 

2> 后来,听说hashtable,因此也有过这种写法,利用hashtable的特性。代码如下(Python):

def two():
    out = {}
    for input_1_item in input_1:
        out[str(input_1_item)] = out.get(str(input_1_item), 0) + 1

    for input_2_item in input_2:
        out[str(input_2_item)] = out.get(str(input_2_item), 0) + 1

    return [int(k) for k,v in out.items() if v > 1]

if __name__ == "__main__":
    print two() 

3> 后来的后来,接触算法分析后,也有过这种写法,先排序,使之成为有规划的数据。代码如下(Python):

def three():
    out = []
    input_1.sort()
    input_2.sort()

    point_1 = 0
    point_2 = 0

    while point_1 < len(input_1) and point_2 < len(input_2):               
        if input_1[point_1] == input_2[point_2]:
            out.append(input_1[point_1])
            point_1 += 1
            point_2 += 1
        elif input_1[point_1] < input_2[point_2]:
            point_1 += 1
        else:
            point_2 += 1

    return out

if __name__ == "__main__":
    print three()

4> N次后来,Python内建的集合运算很给力,简单的使用运算符就可以解决此问题,因此也有过这种写法,代码如下(Python):

def four():
    return list(set(input_1) &  set(input_2))

if __name__ == "__main__":
    print four() 
对于上述这个问题,我相信您可能在使用上述的某种解决方案,既然出现了多种解决方案,您能否快速明了的说出各种方案的优缺点且适应某种场合呢?我相信作为靠谱的程序员一点压力都没有,简直是玩儿似的。那么您是否是靠谱的程序员呢?]]>
http://blog.mrdtime.com/816-Python异常处理对性能影响怎么样?.aspx<![CDATA[Python异常处理对性能影响怎么样?]]>CleverDengWed, 19 Jan 2011 18:00:53 GMThttp://blog.mrdtime.com/816-Python异常处理对性能影响怎么样?.aspx一、糟糕的代码 在使用Python编程语言处理查找列表或字典中的某个数据项时,我经常看到这样的代码(省略具体逻辑):
场景一:
try:
    data_list = find("condition")[0]
except:
    pass

场景二:
try:
    dict_list = find("condition")["key"]
except:
    pass
以上这些代码虽然能够满足程序的功能,但这都不是最佳的实现方式,原因如下:
1、try捕获异常会造成异常(软中断),会影响性能。
2、作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统。

二、糟糕的代码执行时间上的PK

基于上述原因,我与编码者(上述代码作者)交流过,其中的回答“Python对异常的处理方式非常好,从而几乎不影响性能,这也是推荐的一种处理方式”让我好奇,于是做了个小实验---Python异常处理对性能的有多大的影响?源代码如下:
#! /bin/usr/env python
# -*- coding:utf-8 -*-

import time

#统计方法执行的时间
def count_time(func):
    def wrap(*args):
        start = time.time()
        func(*args)
        end = time.time()
        print "func:%s  time:(%0.3f ms)" % (func.func_name, (end-start) * 1000)
    return wrap

#key不存在的时候
@count_time
def not_exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except:
            pass

#key存在的时候
@count_time
def exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except:
            pass

#key不存在的时候并使用Exception
@count_time
def not_exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except Exception, e:
            pass

#key存在的时候并使用Exception
@count_time
def exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except Exception, e:
            pass

#使用防御性编码
@count_time
def not_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        if "not_exists" in dict_list :
            pass
        else:
            pass

def run(max):
    print "max:%s" % max
    not_exists_use_try(max)
    not_exists_use_try_except(max)
    exists_use_try(max)
    exists_use_try_except(max)
    not_use_try(max)

if __name__ == "__main__":
#100
    run(100)
#1,000
    run(1000)
#10,000
    run(10000)
#100,000
    run(100000)
#1,000,000
    run(1000000)
#10,000,000
    run(10000000)
通过对上面的实验程序的3次运行,采样结果如下:
max:100
func:not_exists_use_try  time:(0.110 ms)
func:not_exists_use_try_except  time:(0.110 ms)
func:exists_use_try  time:(0.012 ms)
func:exists_use_try_except  time:(0.011 ms)
func:not_use_try  time:(0.009 ms)

max:1,000
func:not_exists_use_try  time:(0.941 ms)
func:not_exists_use_try_except  time:(1.058 ms)
func:exists_use_try  time:(0.091 ms)
func:exists_use_try_except  time:(0.091 ms)
func:not_use_try  time:(0.063 ms)

max:10,000
func:not_exists_use_try  time:(10.341 ms)
func:not_exists_use_try_except  time:(10.869 ms)
func:exists_use_try  time:(0.879 ms)
func:exists_use_try_except  time:(0.904 ms)
func:not_use_try  time:(0.616 ms)

max:100,000
func:not_exists_use_try  time:(95.245 ms)
func:not_exists_use_try_except  time:(109.051 ms)
func:exists_use_try  time:(9.277 ms)
func:exists_use_try_except  time:(9.290 ms)
func:not_use_try  time:(7.086 ms)

max:1,000,000
func:not_exists_use_try  time:(932.254 ms)
func:not_exists_use_try_except  time:(1088.768 ms)
func:exists_use_try  time:(110.238 ms)
func:exists_use_try_except  time:(104.085 ms)
func:not_use_try  time:(85.284 ms)

max:10,000,000
func:not_exists_use_try  time:(9292.667 ms)
func:not_exists_use_try_except  time:(10858.698 ms)
func:exists_use_try  time:(1037.037 ms)
func:exists_use_try_except  time:(1008.167 ms)
func:not_use_try  time:(812.829 ms)
观察上面的采样结果得知:
一、程序执行时间随着执行的次数同比递增增长。
二、其中使用try...except,Exception的方式会比使用try...except的方式稍花时间,但这点时间可以忽略不计。
三、其中当使用try方式时发生异常比使用try方式时无异常花费时间约10倍。
四、使用防御性方式编码在这几种方式中最花费时间最少。

三、总结

以上数据会根据程序执行环境的不同而得出不同的采样结果,从上面的采样数据结果来看,执行次数在10,000,000级别时候才有明显的延时,抛开性能影响的层面,作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统,这样的好处明显就是性能的提升,同时也加强了程序的可读性。]]>
一、糟糕的代码 在使用Python编程语言处理查找列表或字典中的某个数据项时,我经常看到这样的代码(省略具体逻辑):
场景一:
try:
    data_list = find("condition")[0]
except:
    pass

场景二:
try:
    dict_list = find("condition")["key"]
except:
    pass
以上这些代码虽然能够满足程序的功能,但这都不是最佳的实现方式,原因如下:
1、try捕获异常会造成异常(软中断),会影响性能。
2、作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统。

二、糟糕的代码执行时间上的PK

基于上述原因,我与编码者(上述代码作者)交流过,其中的回答“Python对异常的处理方式非常好,从而几乎不影响性能,这也是推荐的一种处理方式”让我好奇,于是做了个小实验---Python异常处理对性能的有多大的影响?源代码如下:
#! /bin/usr/env python
# -*- coding:utf-8 -*-

import time

#统计方法执行的时间
def count_time(func):
    def wrap(*args):
        start = time.time()
        func(*args)
        end = time.time()
        print "func:%s  time:(%0.3f ms)" % (func.func_name, (end-start) * 1000)
    return wrap

#key不存在的时候
@count_time
def not_exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except:
            pass

#key存在的时候
@count_time
def exists_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except:
            pass

#key不存在的时候并使用Exception
@count_time
def not_exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["not_exists"]
        except Exception, e:
            pass

#key存在的时候并使用Exception
@count_time
def exists_use_try_except(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        try:
            dict_list["do_something"]
        except Exception, e:
            pass

#使用防御性编码
@count_time
def not_use_try(max):
    dict_list = {"do_something":"...."}
    for item in range(0, max):
        if "not_exists" in dict_list :
            pass
        else:
            pass

def run(max):
    print "max:%s" % max
    not_exists_use_try(max)
    not_exists_use_try_except(max)
    exists_use_try(max)
    exists_use_try_except(max)
    not_use_try(max)

if __name__ == "__main__":
#100
    run(100)
#1,000
    run(1000)
#10,000
    run(10000)
#100,000
    run(100000)
#1,000,000
    run(1000000)
#10,000,000
    run(10000000)
通过对上面的实验程序的3次运行,采样结果如下:
max:100
func:not_exists_use_try  time:(0.110 ms)
func:not_exists_use_try_except  time:(0.110 ms)
func:exists_use_try  time:(0.012 ms)
func:exists_use_try_except  time:(0.011 ms)
func:not_use_try  time:(0.009 ms)

max:1,000
func:not_exists_use_try  time:(0.941 ms)
func:not_exists_use_try_except  time:(1.058 ms)
func:exists_use_try  time:(0.091 ms)
func:exists_use_try_except  time:(0.091 ms)
func:not_use_try  time:(0.063 ms)

max:10,000
func:not_exists_use_try  time:(10.341 ms)
func:not_exists_use_try_except  time:(10.869 ms)
func:exists_use_try  time:(0.879 ms)
func:exists_use_try_except  time:(0.904 ms)
func:not_use_try  time:(0.616 ms)

max:100,000
func:not_exists_use_try  time:(95.245 ms)
func:not_exists_use_try_except  time:(109.051 ms)
func:exists_use_try  time:(9.277 ms)
func:exists_use_try_except  time:(9.290 ms)
func:not_use_try  time:(7.086 ms)

max:1,000,000
func:not_exists_use_try  time:(932.254 ms)
func:not_exists_use_try_except  time:(1088.768 ms)
func:exists_use_try  time:(110.238 ms)
func:exists_use_try_except  time:(104.085 ms)
func:not_use_try  time:(85.284 ms)

max:10,000,000
func:not_exists_use_try  time:(9292.667 ms)
func:not_exists_use_try_except  time:(10858.698 ms)
func:exists_use_try  time:(1037.037 ms)
func:exists_use_try_except  time:(1008.167 ms)
func:not_use_try  time:(812.829 ms)
观察上面的采样结果得知:
一、程序执行时间随着执行的次数同比递增增长。
二、其中使用try...except,Exception的方式会比使用try...except的方式稍花时间,但这点时间可以忽略不计。
三、其中当使用try方式时发生异常比使用try方式时无异常花费时间约10倍。
四、使用防御性方式编码在这几种方式中最花费时间最少。

三、总结

以上数据会根据程序执行环境的不同而得出不同的采样结果,从上面的采样数据结果来看,执行次数在10,000,000级别时候才有明显的延时,抛开性能影响的层面,作为靠谱的程序员,应该采取防御性的方式编码,而不应该将错误的处理都丢给系统,这样的好处明显就是性能的提升,同时也加强了程序的可读性。]]>
http://blog.mrdtime.com/808-编程人生---牛人们的故事.aspx<![CDATA[编程人生---牛人们的故事]]>CleverDengTue, 11 Jan 2011 21:33:29 GMThttp://blog.mrdtime.com/808-编程人生---牛人们的故事.aspx “对立志要成为更优秀的程序员的人来说,本书就是他们的圣经”

“看了这本书的读者,职业眼界会更开阔,应该不会再做无谓的重复劳动”

以上文字引用<<编程人生>>封面

很高兴收到图灵出版社<<编程人生>>这本书,这本书汇集了众多杰出的程序员先驱者们的故事,比如Unix,C语言作者之一Ken Thompson、算法巨著<<计算机程序设计艺术>>的作者Donald Knuth。作为热爱编程的一员,能在这里了解到他们对职业生涯的想法以及对编程的看法实在是太棒了,于是收到这本书时,我很激动且毫不保留的将这书推荐给我的同事和朋友(本文的另一作者灾难)。

这本书通过采访的方式并辑录而成,也许在这种谈话方式下其回答可能会不全面,但这是他们最真实最直接的编程感受和体验。从访谈交流的过程中字里行间体会到他们对所从事的工作的热情,并享受以此带来的乐趣。工作而非工作,是生活中的巧克力。因提快程序速度而兴奋;因新出语言特性不合理而愤怒。他们在程序的世界里面享受产品与技术带来的欢乐、抽丝剥茧得到真相的成就,为了计算机领域更加美好的拼搏。

Brad Fitzpatrick在他的程序世界搭建自己的世界,在他的程序世界里面有他的生活,程序中有他的生活乐趣,因为父母看到了孩子喝酒的帖子,想起了“啊,要做个权限了。”;想取笑朋友一篇傻乎乎的文章,“啊,要做个评论的了。”因为觉得有趣而编程,因为编程生活变得有趣。

Jamie Zawinski觉得要从产品的角度去生产,而不是为了抽象而抽象,不能因程序员的过度追求完美而过度设计,有些为了完成功能也许采用了不是很完美的解决方法,可是这样能让产品推出去,而不是成为没人使用过的代码。Douglas Crockford极力反对ECMAScript4纳入ECMAScript语言标准里,努力推进WEB向前发展。作为JavaScript的布道者,从更高的角度去修正ECMAScript规范,以WEB的发展为己责,优雅的编程,用程序写作,从语言的特性出发去了解语言,利用该语言编写优美的程序,就像写散文一般,从艺术的角度解读程序;计算机领域有着产品生产以及计算机科学领域,从他们的谈话中,有些如何在产品生产和计算机科学领域中平衡的观点值得借鉴。

Ken Thompson对于代码的编写认为不是一成不变,当发现了新的程序结构划分或更好的实现方式会修改它,当发现旧的代码实现混乱难于修改便扔掉这些腐烂的代码,对于现有的代码,他的态度是从不迷恋,这也许正应对了我比较认同的一句话“天天重构,每天重构那么点点。”

记录这些谈话并不是漫无目的的,从几个方面和这些软件先驱者进行问答,对于编程语言的想法、对于团队管理的想法、对于编程方式的想法、对于程序产品的想法、对于设计架构的想法、关于编程调试、怎样培养新人的想法。从这本书中得到这些软件先驱者多少年积累下来的经验以及思考,可以从他们的视角去看待这些问题。虽然有些问题解决场景在今天来说并不适合,可是有了他们在这些问题上的探索,我们在解决同类问题时多了些参考与思路。

从他们的经验中得知他们走过怎样的路,什么样的路是失败的路,怎样才是比较好的解决办法,如何去思索现有的问题,如何去解决,当然他们的经验并不对每个人都适用,对于我们这些后来者而言,吸取精华为己所用,体会编程带来的快乐,让我们享受编码的过程吧。]]>
“对立志要成为更优秀的程序员的人来说,本书就是他们的圣经”

“看了这本书的读者,职业眼界会更开阔,应该不会再做无谓的重复劳动”

以上文字引用<<编程人生>>封面

很高兴收到图灵出版社<<编程人生>>这本书,这本书汇集了众多杰出的程序员先驱者们的故事,比如Unix,C语言作者之一Ken Thompson、算法巨著<<计算机程序设计艺术>>的作者Donald Knuth。作为热爱编程的一员,能在这里了解到他们对职业生涯的想法以及对编程的看法实在是太棒了,于是收到这本书时,我很激动且毫不保留的将这书推荐给我的同事和朋友(本文的另一作者灾难)。

这本书通过采访的方式并辑录而成,也许在这种谈话方式下其回答可能会不全面,但这是他们最真实最直接的编程感受和体验。从访谈交流的过程中字里行间体会到他们对所从事的工作的热情,并享受以此带来的乐趣。工作而非工作,是生活中的巧克力。因提快程序速度而兴奋;因新出语言特性不合理而愤怒。他们在程序的世界里面享受产品与技术带来的欢乐、抽丝剥茧得到真相的成就,为了计算机领域更加美好的拼搏。

Brad Fitzpatrick在他的程序世界搭建自己的世界,在他的程序世界里面有他的生活,程序中有他的生活乐趣,因为父母看到了孩子喝酒的帖子,想起了“啊,要做个权限了。”;想取笑朋友一篇傻乎乎的文章,“啊,要做个评论的了。”因为觉得有趣而编程,因为编程生活变得有趣。

Jamie Zawinski觉得要从产品的角度去生产,而不是为了抽象而抽象,不能因程序员的过度追求完美而过度设计,有些为了完成功能也许采用了不是很完美的解决方法,可是这样能让产品推出去,而不是成为没人使用过的代码。Douglas Crockford极力反对ECMAScript4纳入ECMAScript语言标准里,努力推进WEB向前发展。作为JavaScript的布道者,从更高的角度去修正ECMAScript规范,以WEB的发展为己责,优雅的编程,用程序写作,从语言的特性出发去了解语言,利用该语言编写优美的程序,就像写散文一般,从艺术的角度解读程序;计算机领域有着产品生产以及计算机科学领域,从他们的谈话中,有些如何在产品生产和计算机科学领域中平衡的观点值得借鉴。

Ken Thompson对于代码的编写认为不是一成不变,当发现了新的程序结构划分或更好的实现方式会修改它,当发现旧的代码实现混乱难于修改便扔掉这些腐烂的代码,对于现有的代码,他的态度是从不迷恋,这也许正应对了我比较认同的一句话“天天重构,每天重构那么点点。”

记录这些谈话并不是漫无目的的,从几个方面和这些软件先驱者进行问答,对于编程语言的想法、对于团队管理的想法、对于编程方式的想法、对于程序产品的想法、对于设计架构的想法、关于编程调试、怎样培养新人的想法。从这本书中得到这些软件先驱者多少年积累下来的经验以及思考,可以从他们的视角去看待这些问题。虽然有些问题解决场景在今天来说并不适合,可是有了他们在这些问题上的探索,我们在解决同类问题时多了些参考与思路。

从他们的经验中得知他们走过怎样的路,什么样的路是失败的路,怎样才是比较好的解决办法,如何去思索现有的问题,如何去解决,当然他们的经验并不对每个人都适用,对于我们这些后来者而言,吸取精华为己所用,体会编程带来的快乐,让我们享受编码的过程吧。]]>
http://blog.mrdtime.com/744-单点登录解决方案.aspx<![CDATA[单点登录解决方案]]>CleverDengSat, 28 Aug 2010 03:03:18 GMThttp://blog.mrdtime.com/744-单点登录解决方案.aspx

一、何谓单点登录

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

二、场景

话说现在有很多在线运营的网站,各自都维护着登录口。之前的需求从A站跳到C站必须2个站点都需要登陆一次,而现在的需求发生了变法,为了提高用户体验,只需要用户在A,C这2站中任一站登陆即可横穿A,C这2个站点,那么我们将要参与什么方法解决这一问题呢?

三、解决方案

对于该问题的解决方案,我想读者能够百度,谷歌一搜,很容易找到相关的文章,但根据我的观察,一般介绍的解决方案都是使用统一验证中心验证,然后将标识码植入url中,从而完成了子域名或跨域多个站点的单点登录。而我将要介绍的是一种网络上鲜为人介绍的方案,有点类似于计算机网络中的“广播”。
广播,顾名思义,一中心点根据一定的规则向满足该规则的分节点传递相同的信息。那么根据这一概念,可以很巧妙的利用这一思想解决单点登录的问题。原理如下图:
上图中,方向箭头指向“登录中心”的为用户登录请求路线,该节点为中心节点,方向箭头从“登录中心”分发出去的,为发送消息至各个满足规则的站点,即开始“广播”这一动作。
那么我们很容易理解,每个需要集群单点登录的站点只需要提供一个供登录中心统一访问的接口即可,登录中心验证成功后将按照一定的规则开始广播。接受广播的站点只需按照自己的具体用户实现自己的功能比如写cookie、session等。从而实现跨域或多站点统一登录。

四、总结

本篇文章只分享了单点登录模块的解决思路,因为该模块是用户管理中心的一个子集,因此就没有提供具体代码(牵扯的底层服务比较多),具体实现还是要靠各位读者,我坚信思想比丢出来的代码更重要。
]]>

一、何谓单点登录

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

二、场景

话说现在有很多在线运营的网站,各自都维护着登录口。之前的需求从A站跳到C站必须2个站点都需要登陆一次,而现在的需求发生了变法,为了提高用户体验,只需要用户在A,C这2站中任一站登陆即可横穿A,C这2个站点,那么我们将要参与什么方法解决这一问题呢?

三、解决方案

对于该问题的解决方案,我想读者能够百度,谷歌一搜,很容易找到相关的文章,但根据我的观察,一般介绍的解决方案都是使用统一验证中心验证,然后将标识码植入url中,从而完成了子域名或跨域多个站点的单点登录。而我将要介绍的是一种网络上鲜为人介绍的方案,有点类似于计算机网络中的“广播”。
广播,顾名思义,一中心点根据一定的规则向满足该规则的分节点传递相同的信息。那么根据这一概念,可以很巧妙的利用这一思想解决单点登录的问题。原理如下图:
上图中,方向箭头指向“登录中心”的为用户登录请求路线,该节点为中心节点,方向箭头从“登录中心”分发出去的,为发送消息至各个满足规则的站点,即开始“广播”这一动作。
那么我们很容易理解,每个需要集群单点登录的站点只需要提供一个供登录中心统一访问的接口即可,登录中心验证成功后将按照一定的规则开始广播。接受广播的站点只需按照自己的具体用户实现自己的功能比如写cookie、session等。从而实现跨域或多站点统一登录。

四、总结

本篇文章只分享了单点登录模块的解决思路,因为该模块是用户管理中心的一个子集,因此就没有提供具体代码(牵扯的底层服务比较多),具体实现还是要靠各位读者,我坚信思想比丢出来的代码更重要。
]]>
http://blog.mrdtime.com/728-使用委托,满足不同的场景,开放封闭原则.aspx<![CDATA[使用委托,满足不同的场景,开放封闭原则]]>CleverDengSun, 16 May 2010 18:04:04 GMThttp://blog.mrdtime.com/728-使用委托,满足不同的场景,开放封闭原则.aspx委托是虾米 根绝国际惯例,先借用隐喻的强大威力说说委托是啥,委托:将自己的事务嘱托他人代为处理。那么计算机中的委托概念呢?大同小可。
在现实生活中,这样的场景天天都在发生。比如老王的项目快上线了,可是当月的报销少了通讯费的发票,这咋办了?不用急,把话费钱给小张,委托小张童鞋代缴,而小张是个好同志呀,不用打的,做公交车去。老王想起了上次小邓同学同样帮我代缴通讯费,几个站的路却玩享受坐的奔过去的。那么在程序的世界里是不是也有这种场景的映射呢?当然有,时时有,不然就没本篇博文了,本文通过Javascript的一个应用场景分享一次重构的心得。

JavaScript使用Ajax发表评论、留言

在我自己维护的CleverDeng时光个人博客里,用户互动的都是运行了Ajax技术,而Ajax的实现是利用了Jquery这个框架,那么我在开发的前期,是这样完成这2个功能的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);
}
function SendPost(content)
{
    jQuery.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
        ShowInfo("热心提示:"+showmsg+"...");
     }
   });
   return false;
}
OK,这就是前期结构,看似很不错,代码的重复利用率也比较高,每个功能都只需要构造好发送的数据,统一利用SendPost()这个方法接口统一发出Ajax请求,然后将回传的数据显示出来。其实这个结构面对个性化的需求场景就难免力不从心了,因为我们可以看到这个结构的最后处理方式都是一致的。比如发表评论后需要及时看到更新的数据呢或发表留言需要及时看到更新的留言信息呢?

提升用户体验,重构、重构、再重构

有新的需求了,某日,一朋友在浏览我的博客时告诉我,评论发表后需要刷新才能看到我的评论了,体验不好哟。这个问题,我还是非常清楚的,但是由于原有结构不太愿意动手去修改,一直留到现在迟迟没动手,但最近在对博客的皮肤结构调整时,因此也动了重构的念头。那么中间就有了个选择方案的过程。第一个思考方案是这样的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);
}
function SendPost(content)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
       var type=msg.split('^')[0];
       var showmsg=msg.split('^')[1];
       if("message"==type)
       {
          ShowInfo("热心提示:发表评论成功...");
          $("#mark").html(msg);
          return false;
        }
        if("mark"==type)
        {
           ShowInfo("热心提示:发表留言成功...");
           $("#message").html(msg);
           return false;
        }
     }
   });
   return false;
}
OK,这个想象的实现结构就如上面所描叙,对比第一种实现方式(初期的实现),不同之处在于回调方法中写了If判断实现不同的需求场景,同时还需要服务器端的回传数据按照一定格式。也许有人在想,恩,这个方式是不错,把变法都封装在发送请求的数据中(url链接字串中的参数)和回传的数据中,当初确实是这样想象的,但马上被否定了,一、原因是发表评论与获取最新的评论捆绑在一个方法请求里,也许某天我不需要发表评论后就立即看到最新的数据呢?二、如果以后有(顶、踩)等等类似的功能呢?难道每次的改动就需要加If判断吗?那我无法想象以后还有激情维护自己的这个博客了。好吧,那么再想想。怎么把变法的部分封装起来,使其对扩展开放,修改关闭呢?恩,NET中的委托在JavaScript中也能使用吗?这一想法一出,马上做了个Demo,运行效果不错。因此就有了第二种实现方式。

使用委托代理,满足执行过程相同,执行方式不同

根据前面的简叙,我们知道这个功能场景跟本文开始处举例的场景类似,大体执行的过程相同,但是执行方式不同。前面说过委托代理不同的同事去完成代缴通讯费,他们实现的方式截然不同。那么其实变法在于委托人(代理人)不同而已,真对发表评论和留言这2个功能场景,我们只需编写不同的回调方法,再次重构后的实现是这样的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData,markcallback);
}
function markcallback(msg)
{
   ShowInfo("热心提示:发表评论成功...");
   $("#mark").html(msg);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData,messagecallback);
}
function messagecallbak(msg)
{
   ShowInfo("热心提示:发表留言成功...");
   $("#message").html(msg);
}

function SendPost(content,m)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
        m(msg);
     }
   });
   return false;
}

OK,通过上面这个是用委托的重构,我们能够发现,统一的发出Ajax请求的方法在回调方法时已经没有If判断,而只是充当了代理者的身份,二具体的实现却根据具体的场景。因此到此我已经很满意这个结构了,比如我日后需要个(顶,踩)的功能,只需要扩展顶与踩的方法和具体的回调方法。而不必去修改统一的发出Ajax请求的接口。

总结

通过本文的描叙一个简单的应用场景,一步一步的重构满足以知的需求,正如上文所说,如果我们以后需要扩展一个(顶、踩)的功能呢,同样只也需定义好回调的方法,同样使用这套统一的Ajax的请求接口以满足需求,最后我们发现使用委托代理的方法对比之前的实现或构想更为灵活,是否刚好印证了前辈们所说的向修改封闭,向扩展开放的的开放封闭原则了。欢迎分享您的观点,在交流中成长。]]>
委托是虾米 根绝国际惯例,先借用隐喻的强大威力说说委托是啥,委托:将自己的事务嘱托他人代为处理。那么计算机中的委托概念呢?大同小可。
在现实生活中,这样的场景天天都在发生。比如老王的项目快上线了,可是当月的报销少了通讯费的发票,这咋办了?不用急,把话费钱给小张,委托小张童鞋代缴,而小张是个好同志呀,不用打的,做公交车去。老王想起了上次小邓同学同样帮我代缴通讯费,几个站的路却玩享受坐的奔过去的。那么在程序的世界里是不是也有这种场景的映射呢?当然有,时时有,不然就没本篇博文了,本文通过Javascript的一个应用场景分享一次重构的心得。

JavaScript使用Ajax发表评论、留言

在我自己维护的CleverDeng时光个人博客里,用户互动的都是运行了Ajax技术,而Ajax的实现是利用了Jquery这个框架,那么我在开发的前期,是这样完成这2个功能的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);
}
function SendPost(content)
{
    jQuery.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
        ShowInfo("热心提示:"+showmsg+"...");
     }
   });
   return false;
}
OK,这就是前期结构,看似很不错,代码的重复利用率也比较高,每个功能都只需要构造好发送的数据,统一利用SendPost()这个方法接口统一发出Ajax请求,然后将回传的数据显示出来。其实这个结构面对个性化的需求场景就难免力不从心了,因为我们可以看到这个结构的最后处理方式都是一致的。比如发表评论后需要及时看到更新的数据呢或发表留言需要及时看到更新的留言信息呢?

提升用户体验,重构、重构、再重构

有新的需求了,某日,一朋友在浏览我的博客时告诉我,评论发表后需要刷新才能看到我的评论了,体验不好哟。这个问题,我还是非常清楚的,但是由于原有结构不太愿意动手去修改,一直留到现在迟迟没动手,但最近在对博客的皮肤结构调整时,因此也动了重构的念头。那么中间就有了个选择方案的过程。第一个思考方案是这样的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);
}
function SendPost(content)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
       var type=msg.split('^')[0];
       var showmsg=msg.split('^')[1];
       if("message"==type)
       {
          ShowInfo("热心提示:发表评论成功...");
          $("#mark").html(msg);
          return false;
        }
        if("mark"==type)
        {
           ShowInfo("热心提示:发表留言成功...");
           $("#message").html(msg);
           return false;
        }
     }
   });
   return false;
}
OK,这个想象的实现结构就如上面所描叙,对比第一种实现方式(初期的实现),不同之处在于回调方法中写了If判断实现不同的需求场景,同时还需要服务器端的回传数据按照一定格式。也许有人在想,恩,这个方式是不错,把变法都封装在发送请求的数据中(url链接字串中的参数)和回传的数据中,当初确实是这样想象的,但马上被否定了,一、原因是发表评论与获取最新的评论捆绑在一个方法请求里,也许某天我不需要发表评论后就立即看到最新的数据呢?二、如果以后有(顶、踩)等等类似的功能呢?难道每次的改动就需要加If判断吗?那我无法想象以后还有激情维护自己的这个博客了。好吧,那么再想想。怎么把变法的部分封装起来,使其对扩展开放,修改关闭呢?恩,NET中的委托在JavaScript中也能使用吗?这一想法一出,马上做了个Demo,运行效果不错。因此就有了第二种实现方式。

使用委托代理,满足执行过程相同,执行方式不同

根据前面的简叙,我们知道这个功能场景跟本文开始处举例的场景类似,大体执行的过程相同,但是执行方式不同。前面说过委托代理不同的同事去完成代缴通讯费,他们实现的方式截然不同。那么其实变法在于委托人(代理人)不同而已,真对发表评论和留言这2个功能场景,我们只需编写不同的回调方法,再次重构后的实现是这样的。(基本结构,具体实现略)
//文章评论
function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData,markcallback);
}
function markcallback(msg)
{
   ShowInfo("热心提示:发表评论成功...");
   $("#mark").html(msg);
}
//留言
function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData,messagecallback);
}
function messagecallbak(msg)
{
   ShowInfo("热心提示:发表留言成功...");
   $("#message").html(msg);
}

function SendPost(content,m)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },
     success: function(msg) {
        m(msg);
     }
   });
   return false;
}

OK,通过上面这个是用委托的重构,我们能够发现,统一的发出Ajax请求的方法在回调方法时已经没有If判断,而只是充当了代理者的身份,二具体的实现却根据具体的场景。因此到此我已经很满意这个结构了,比如我日后需要个(顶,踩)的功能,只需要扩展顶与踩的方法和具体的回调方法。而不必去修改统一的发出Ajax请求的接口。

总结

通过本文的描叙一个简单的应用场景,一步一步的重构满足以知的需求,正如上文所说,如果我们以后需要扩展一个(顶、踩)的功能呢,同样只也需定义好回调的方法,同样使用这套统一的Ajax的请求接口以满足需求,最后我们发现使用委托代理的方法对比之前的实现或构想更为灵活,是否刚好印证了前辈们所说的向修改封闭,向扩展开放的的开放封闭原则了。欢迎分享您的观点,在交流中成长。]]>