• Tag:

     

    貌似在各行各业的工作中,人的问题永远是一切问题的根源所在。时至今日,在中国的很多软件公司/部门,却慢慢的忽视了这个问题,尤其是管理层。所以,很多公司,尤其是不以软件开发为住的公司中的IT部门,永远是公司节源的重点。为了“节约成本”,搞人海战术,而真正达到预期的项目又有多少?

    值得庆幸的是,我作为一名开发人员,所在的公司对人的问题还是相当重视的,可即便如此,每天的工作中所遇到的问题,仍会引发我对人的重要性的感慨~~

    项目 1:

    在之前的一个项目中,是个成熟度很高的团队,最高开发经验为10年,最低的开发经验超过了3年。并且,每个人都对软件和代码的质量都非常重视(有些人,则追求到了完美的地步)。然而,作为一个敏捷团队,在每天超快的工作节奏中,大家保持着很频繁的沟通和交流,Session,Pair programming, story kick off。。。但是让所有人困惑的是,为什么由这些优秀的开发人员所组成的开发团队,讨论问题始终存在一些分歧,谁都无法说服谁。最终的选择,总是要有某些/人,很无奈的妥协而达成。沟通效率的低下,困惑了所有的人。

    到底问题出在哪里?一群没有领头羊的狼,不是一个好团队?完全扁平的团队组织,行不通?

    项目 2:

    目前正在做的一个项目组,人员结构很复杂:有客户自己从其他不同IT部门调配的人(能力参差不齐),有外包公司的人,还有我们自己的TWer。人员配比为(Twer: Non-Twer = 1:4)。在技术上TWer是领头羊,但是在组织结构上,他们仍旧隶属于自己的部门,他们与项目的成败,没有直接关系。Twer承担着交付压力。所以,这就决定了他们从工作动力和态度上都不可能与Twer完全一样。再加上Coding能力的差别,就导致了部分人有混日子的状态。

    为了提高开发效率,我们采取的措施:

    1. 跟Non-TWer结对开发,从中发掘可造之材,重点培养,然后让培养出来的人,再去跟其他Non-TWer结对。从而,解决我们人手不够的问题。

    2. 实施严格的Code-review,目的首先是检验大家写的代码,是否存在问题,从而保证代码质量。同时,可以让每个人都意识到,要负责的写每行代码,否则,就会让受到别人的“chanllenge”.

    3. 让客户IT部门的开发人员,负责于他们内部系统连接的接口部分。这样做的主要原因,是因为他们对自己的内部系统比较熟悉,而且,他们认识内部系统的负责人。对于开发和以后的连调测试,都有帮助。

    4. 做Session,把大家都要掌握的技能和编程思想,都统统灌输给每个人。推荐他们读类似《clean code》之类的书,让大家自己主动学。但事实证明,让他们主动学的期望,有点高了。毕竟,最初的组织结构就已经决定了这个结果。

    5. 项目后期,接口部分的开发成了项目的瓶颈。有的接口,需求久久搞不清楚;有的接口,环境迟迟不能到位。我们的人就开始介入接口开发,发现他们内部系统的开发人员安排和开发排期相当复杂,根本达不到我们的期望上线时间。于是,我们就争取让他们内部系统的开发人员飞过来,跟我坐在一起工作。事实证明,这样做效率是最高的。但是,不幸的是,并不是所有内部系统部门都能派人过来。

    其中,我们做的不好地方也有很多:

    1. 无条件的接受了客户安排的所有人,并且没有淘汰任何“混日子”的人。

    2. 没有找到摆正Non-TWer工作态度的关键点。以至于,有些人动不动就在工作时间,跑出去办自己的私事了。

    3. 由于交付压力日渐加到,我们对Non-Twer的培养做的不够好,Session慢慢变少。

  • 老了 - [Thoughts]2011-08-17

    Tag:

    突然觉得“老了”很恐怖

    今天我让姐姐替我买火车票,说了两次是买到徐州的,结果还是买了到上海的。。。

    我很生气,接完电话后,把手机仍了老远。因为我就是想不通,为什么会这样。我印象中,姐姐一直是伶牙俐齿的人,怎么突然间脑子不管事了。

    以前姥姥还教我翻筋斗,给我编竹楼,可以现在虽然身体很健康,可是眼睛什么都不看清楚了,耳朵也不不好使了。即使我站在她一米以内的距离,她都认不清楚我了。。。

    爸妈今年退休了,妈妈打算把生意让嫂子做,说是,老了,脑子不好使了。

    这都是,这一年里突然间让我感受到事情。

    我心里一直还拗不过,总是想,怎么会这样。

    可是现在突然想,如果我到了他们的年纪,是不是也会像他们一样。这种想法让我觉得很恐怖。

    要是真的那样,该怎么办啊。。。

    人的成长不是自己孤零零的长大,而是身下一波波的孩子催着你长大,还有长辈们慢慢拉着你一起变老。

    因为,老人们已经听不懂你的那一堆的if 。。 else 。。,孩子们理解不了你的那套should do。

  • Tag: JPA
    • JPA Mapping

    1.      JPA 中可以根据2Table之间的外键关系,建立2domain的单向和双向关联关系。如果建立双向关联,则需要在2domain class中声明引用,并在关系拥有者里面指定关系,而另外一个class使用“mappedBy”声明关系拥有者,例如,@ManyToMany(mappedBy="attributeOfTheOwningClass") 

    举例说明:

    (1)     ManyToOne

    Create Table Employee{

    DEPT_ID NUMBER(19, 0) NOT NULL,

    FOREIGN KEY(DEPT_ID) REFERENCES Department(ID)

    }

    Create Table Department{

    ID NUMBER(19, 0) NOT NULL

    }

     

    @Entity

    Public class Employee{

    @ManyToOne

    @JoinColumn(name=”DEPT_ID”)

    Private Department  department;

    }

    @Entity

    Public class Department{

    @OneToMany(mappedBy=”department”)

    Private Collection employees;

    }

    (2)     OneToOne

     

    Create Table Employee{

    DEPT_ID NUMBER(19, 0) NOT NULL,

    FOREIGN KEY(PSPACE_ID) REFERENCES ParkingSpace(ID)

    }

    Create Table ParkingSpace{

    ID NUMBER(19, 0) NOT NULL

    }

     

    @Entity

    Public class Employee{

    @OneToOne

    @JoinColumn(name=”PSPACE_ID”)

    Private ParkingSpace parkingSpace;

    @Entity

    Public class ParkingSpace{
    @OneToOne(mappedBy=” parkingSpace”)

    Private Employee employee;

    }

     

    •  JPA default fetch type is as following

     

    @OneToMany and @ManyToMany 关系的默认FetchType LAZY

    @OneToOne and @ManyToOne 关系的默认 FetchTypeEAGER

    reference为集合的fetch type Lazy, 看上去还是比较有道理的。但是如果记不清的话,可以根据自己的需要统统声明一下。毕竟这些默认设置和Hibernate是不同的。

    例如:

       (1)

        @OneToOne(cascade = CascadeType.ALL)  // default  fetch type for OneToOne is eager

        @JoinColumn(name = "INSURANCE_POLICY_ID")

        private InsurancePolicy policy; 

        (2)

        @OneToMany(cascade = CascadeType.ALL) // default fetch type for OneToMany  is lazy

        @JoinColumn(name = "LOAN_ID")

     private List repaymentPlans;

     

    • N+1问题

     

    Usually this happens when the UI displays a table of entities, where the entities have lazy many-to-one associations that are navigated in Java code. By default, there will be one select for the main query, and one select for each entity returned for each many-to-one association. If there are many entities, this will bombard the database with queries.

     

      1. Use left join fetch - Fetch the entities up front in the main query.

       2. Use batch size - Set an appropriate batch size for collections and entities. When one entity in an association is lazily loaded, Hibernate will pre-fetch other instances of that same entity that have proxies in the Persistence Context (Session).

       3. Use side-effect queries - Execute JPAQL queries to initialize the entities that will be referenced, discarding the results.

    推荐文章:http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping

  • About SSH - [Ubuntu]2011-07-30

    Tag: ssh

    SSH的英文全称是Secure SHell。通过使用SSH,你可以把所有传输的数据进行加密,这样"中间人"这种攻击方式就不可能实现了,而且也能够防止DNS和IP欺骗。还有一个额外的好处就是传输的数据是经过压缩的,所以可以加快传输的速度。SSH有很多功能,它既可以代替telnet,又可以为ftp、pop、甚至ppp提供一个安全的"通道"。

    统的网络服务程序,如:ftp、pop和telnet在本质上都是不安全的,因为它们在网络上用明文传送口令和数据,别有用心的人非常容易就可以截获这些口令和数据。而且,这些服务程序的安全验证方式也是有其弱点的,就是很容易受到"中间人"(man-in-the-middle)这种方式的攻击。所谓"中间人"的攻击方式,就是"中间人"冒充真正的服务器接收你的传给服务器的数据,然后再冒充你把数据传给真正的服务器。服务器和你之间的数据传送被 "中间人"一转手做了手脚之后,就会出现很严重的问题。

    最初SSH是由芬兰的一家公司开发的。但是因为受版权和加密算法的限制,现在很多人都转而使用OpenSSH。OpenSSH是SSH的替代软件,而且是免费的,可以预计将来会有越来越多的人使用它而不是SSH。
    SSH是由客户端和服务端的软件组成的,有两个不兼容的版本分别是:1.x和2.x。用SSH 2.x的客户程序是不能连接到SSH 1.x的服务程序上去的。OpenSSH 2.x同时支持SSH 1.x和2.x。

    如果要实现ssh连通,需要在server端安装 OpenSSH-server

    SSH的安全验证是如何工作的

    从客户端来看,SSH提供两种级别的安全验证。
    第一种级别(基于口令的安全验证)只要你知道自己帐号和口令,就可以登录到远程主机。所有传输的数据都会被加密,但是不能保证你正在连接的服务器就是你想连接的服务器。可能会有别的服务器在冒充真正的服务器,也就是受到"中间人"这种方式的攻击。
    第二种级别(基于密匙的安全验证)需要依靠密匙,也就是你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后,先在你在该服务器的家目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。如果两个密匙一致,服务器就用公用密匙加密"质询"(challenge)并把它发送给客户端软件。客户端软件收到"质询"之后就可以用你的私人密匙解密再把它发送给服务器。
    用这种方式,你必须知道自己密匙的口令。但是,与第一种级别相比,第二种级别不需要在网络上传送口令。
    第二种级别不仅加密所有传送的数据,而且"中间人"这种攻击方式也是不可能的(因为他没有你的私人密匙)。但是整个登录的过程可能需要10秒。

    安装并测试OpenSSH

    因为受到美国法律的限制,在很多Linux的发行版中都没有包括OpenSSH。但是,可以从网络上下载并安装OpenSSH(有关OpenSSH的安装和配置请参考:http://www.linuxaid.com.cn/engineer/brimmer/html/OpenSSH.htm)。
    安装完OpenSSH之后,用下面命令测试一下:
    ssh -l [your accountname on the remote host] [address of the remote host]
    如果OpenSSH工作正常,你会看到下面的提示信息:
    The authenticity of host [hostname] can't be established.
    Key fingerprint is 1024 5f:a0:0b:65:d3:82:df:ab:44:62:6d:98:9c:fe:e9:52.
    Are you sure you want to continue connecting (yes/no)?
    OpenSSH告诉你它不知道这台主机,但是你不用担心这个问题,因为你是第一次登录这台主机。键入"yes"。这将把这台主机的"识别标记"加到"~/.ssh/know_hosts"文件中。第二次访问这台主机的时候就不会再显示这条提示信息了。
    然后,SSH提示你输入远程主机上你的帐号的口令。输入完口令之后,就建立了SSH连接,这之后就可以象使用telnet那样使用SSH了。

    SSH的密匙

    生成你自己的密匙对

    生成并分发你自己的密匙有两个好处:
    1) 可以防止"中间人"这种攻击方式
    2) 可以只用一个口令就登录到所有你想登录的服务器上
    用下面的命令可以生成密匙:
    ssh-keygen
    如果远程主机使用的是SSH 2.x就要用这个命令:
    ssh-keygen -d
    在同一台主机上同时有SSH1和SSH2的密匙是没有问题的,因为密匙是存成不同的文件的。
    ssh-keygen命令运行之后会显示下面的信息:
    Generating RSA keys: ............................ooooooO......ooooooO
    Key generation complete.
    Enter file in which to save the key (/home/[user]/.ssh/identity):
    [按下ENTER就行了]
    Created directory '/home/[user]/.ssh'.
    Enter passphrase (empty for no passphrase):
    [输入的口令不会显示在屏幕上]
    Enter same passphrase again:
    [重新输入一遍口令,如果忘记了口令就只能重新生成一次密匙了]
    Your identification has been saved in /home/[user]/.ssh/identity.
    [这是你的私人密匙]
    Your public key has been saved in /home/[user]/.ssh/identity.pub.
    The key fingerprint is: 2a:dc:71:2f:27:84:a2:e4:a1:1e:a9:63:e2:fa:a5:89 [user]@[local machine]
    "ssh-keygen -d"做的是几乎同样的事,但是把一对密匙存为(默认情况下)"/home/[user]/.ssh/id_dsa"(私人密匙)和"/home/[user]/.ssh/id_dsa.pub"(公用密匙)。
    现在你有一对密匙了:公用密匙要分发到所有你想用ssh登录的远程主机上去;私人密匙要好好地保管防止别人知道你的私人密匙。用"ls -l ~/.ssh/identity"或"ls -l ~/.ssh/id_dsa"所显示的文件的访问权限必须是"-rw-------"。
    如果你怀疑自己的密匙已经被别人知道了,不要迟疑马上生成一对新的密匙。当然,你还要重新分发一次公用密匙。

    分发公用密匙

    在每一个你需要用SSH连接的远程服务器上,你要在自己的家目录下创建一个".ssh"的子目录,把你的公用密匙"identity.pub" 拷贝到这个目录下并把它重命名为"authorized_keys"。然后执行:
    chmod 644 .ssh/authorized_keys
    这一步是必不可少的。如果除了你之外别人对"authorized_keys"文件也有写的权限,SSH就不会工作。
    如果你想从不同的计算机登录到远程主机,"authorized_keys"文件也可以有多个公用密匙。在这种情况下,必须在新的计算机上重新生成一对密匙,然后把生成的"identify.pub"文件拷贝并粘贴到远程主机的"authorized_keys"文件里。当然在新的计算机上你必须有一个帐号,而且密匙是用口令保护的。有一点很重要,就是当你取消了这个帐号之后,别忘了把这一对密匙删掉。

    配置SSH

    配置客户端的软件

    OpenSSH 有三种配置方式:命令行参数、用户配置文件和系统级的配置文件("/etc/ssh/ssh_config")。命令行参数优先于配置文件,用户配置文件优先于系统配置文件。所有的命令行的参数都能在配置文件中设置。因为在安装的时候没有默认的用户配置文件,所以要把 "/etc/ssh/ssh_config"拷贝并重新命名为"~/.ssh/config"。
    标准的配置文件大概是这样的:
    [lots of explanations and possible options listed]
    # Be paranoid by default
    Host *
    ForwardAgent no
    ForwardX11 no
    FallBackToRsh no
    还有很多选项的设置可以用"man ssh"查看"CONFIGURATION FILES"这一章。
    配置文件是按顺序读取的。先设置的选项先生效。
    假定你在www.foobar.com上有一个名为"bilbo"的帐号。而且你要把"ssh-agent"和"ssh-add"结合起来使用并且使用数据压缩来加快传输速度。因为主机名太长了,你懒得输入这么长的名字,用"fbc"作为"www.foobar.com"的简称。你的配置文件可以是这样的:
    Host *fbc
    HostName www.foobar.com
    User bilbo
    ForwardAgent yes
    Compression yes
    # Be paranoid by default
    Host *
    ForwardAgent no
    ForwardX11 no
    FallBackToRsh no
    你输入"ssh fbc"之后,SSH会自动地从配置文件中找到主机的全名,用你的用户名登录并且用"ssh-agent"管理的密匙进行安全验证。这样很方便吧!
    用SSH连接到其它远程计算机用的还是"paranoid(偏执)"默认设置。如果有些选项没有在配置文件或命令行中设置,那么还是使用默认的"paranoid"设置。
    在我们上面举的那个例子中,对于到www.foobar.com的SSH连接:"ForwardAgent"和"Compression"被设置为 "Yes";其它的设置选项(如果没有用命令行参数)"ForwardX11"和"FallBackToRsh"都被设置成"No"。
    其它还有一些需要仔细看一看的设置选项是:
    l CheckHostIP yes
    这个选项用来进行IP地址的检查以防止DNS欺骗。
    l CompressionLevel
    压缩的级别从"1"(最快)到"9"(压缩率最高)。默认值为"6"。
    l ForwardX11 yes
    为了在本地运行远程的X程序必须设置这个选项。
    l LogLevel DEBUG
    当SSH出现问题的时候,这选项就很有用了。默认值为"INFO"。

    配置服务端的软件

    SSH服务器的配置使用的是"/etc/ssh/sshd_config"配置文件,这些选项的设置在配置文件中已经有了一些说明而且用"man sshd"也可以查看帮助。请注意OpenSSH对于SSH 1.x和2.x没有不同的配置文件。
    在默认的设置选项中需要注意的有:
    l PermitRootLogin yes
    最好把这个选项设置成"PermitRootLogin without-password",这样"root"用户就不能从没有密匙的计算机上登录。把这个选项设置成"no"将禁止"root"用户登录,只能用"su"命令从普通用户转成"root"。
    l X11Forwarding no
    把这个选项设置成"yes"允许用户运行远程主机上的X程序。就算禁止这个选项也不能提高服务器的安全因为用户可以安装他们自己的转发器(forwarder),请参看"man sshd"。
    l PasswordAuthentication yes
    把这个选项设置为"no"只允许用户用基于密匙的方式登录。这当然会给那些经常需要从不同主机登录的用户带来麻烦,但是这能够在很大程度上提高系统的安全性。基于口令的登录方式有很大的弱点。
    l # Subsystem /usr/local/sbin/sftpd
    把最前面的#号去掉并且把路径名设置成"/usr/bin/sftpserv",用户就能使用"sftp"(安全的FTP)了(sftpserv在sftp 软件包中)。因为很多用户对FTP比较熟悉而且"scp"用起来也有一些麻烦,所以"sftp"还是很有用的。而且2.0.7版本以后的图形化的ftp工具"gftp"也支持"sftp"。

    拷贝文件

    用"scp"拷贝文件

    SSH提供了一些命令和shell用来登录远程服务器。在默认情况下它不允许你拷贝文件,但是还是提供了一个"scp"命令。
    假定你想把本地计算机当前目录下的一个名为"dumb"的文件拷贝到远程服务器www.foobar.com上你的家目录下。而且你在远程服务器上的帐号名为"bilbo"。可以用这个命令:
    scp dumb bilbo@www.foobar.com:.
    把文件拷贝回来用这个命令:
    scp bilbo@www.foobar.com:dumb .
    "scp"调用SSH进行登录,然后拷贝文件,最后调用SSH关闭这个连接。
    如果在你的"~/.ssh/config"文件中已经为www.foobar.com做了这样的配置:
    Host *fbc
    HostName www.foobar.com
    User bilbo
    ForwardAgent yes
    那么你就可以用"fbc"来代替"bilbo@www.foobar.com",命令就简化为"scp dumb fbc:."。
    "scp"假定你在远程主机上的家目录为你的工作目录。如果你使用相对目录就要相对于家目录。
    用"scp"命令的"-r"参数允许递归地拷贝目录。"scp"也可以在两个不同的远程主机之间拷贝文件。
    有时候你可能会试图作这样的事:用SSH登录到www.foobar.com上之后,输入命令"scp [local machine]:dumb ."想用它把本地的"dumb"文件拷贝到你当前登录的远程服务器上。这时候你会看到下面的出错信息:
    ssh: secure connection to [local machine] refused
    之所以会出现这样的出错信息是因为你运行的是远程的"scp"命令,它试图登录到在你本地计算机上运行的SSH服务程序……所以最好在本地运行"scp"除非你的本地计算机也运行SSH服务程序。

    用"sftp"拷贝文件

    如果你习惯使用ftp的方式拷贝文件,可以试着用"sftp"。"sftp"建立用SSH加密的安全的FTP连接通道,允许使用标准的ftp命令。还有一个好处就是"sftp"允许你通过"exec"命令运行远程的程序。从2.0.7版以后,图形化的ftp客户软件"gftp"就支持"sftp"。
    如果远程的服务器没有安装sftp服务器软件"sftpserv",可以把"sftpserv"的可执行文件拷贝到你的远程的家目录中(或者在远程计算机的 $PATH环境变量中设置的路径)。"sftp"会自动激活这个服务软件,你没有必要在远程服务器上有什么特殊的权限。

    用"rsync"拷贝文件

    "rsync" 是用来拷贝、更新和移动远程和本地文件的一个有用的工具,很容易就可以用"-e ssh"参数和SSH结合起来使用。"rsync"的一个优点就是,不会拷贝全部的文件,只会拷贝本地目录和远程目录中有区别的文件。而且它还使用很高效的压缩算法,这样拷贝的速度就很快。

    用"加密通道"的ftp拷贝文件

    如果你坚持要用传统的FTP客户软件。SSH可以为几乎所有的协议提供"安全通道"。FTP是一个有一点奇怪的协议(例如需要两个端口)而且不同的服务程序和服务程序之间、客户程序和客户程序之间还有一些差别。
    实现"加密通道"的方法是使用"端口转发"。你可以把一个没有用到的本地端口(通常大于1000)设置成转发到一个远程服务器上,然后只要连接本地计算机上的这个端口就行了。有一点复杂是吗?
    其实一个基本的想法就是,转发一个端口,让SSH在后台运行,用下面的命令:
    ssh [user@remote host] -f -L 1234:[remote host]:21 tail -f /etc/motd
    接着运行FTP客户,把它设置到指定的端口:
    lftp -u [username] -p 1234 localhost
    当然,用这种方法很麻烦而且很容易出错。所以最好使用前三种方法。

    用SSH设置"加密通道"

    "加密通道"的基础知识

    SSH 的"加密通道"是通过"端口转发"来实现的。你可以在本地端口(没有用到的)和在远程服务器上运行的某个服务的端口之间建立"加密通道"。然后只要连接到本地端口。所有对本地端口的请求都被SSH加密并且转发到远程服务器的端口。当然只有远程服务器上运行SSH服务器软件的时候"加密通道"才能工作。可以用下面命令检查一些远程服务器是否运行SSH服务:
    telnet [full name of remote host] 22
    如果收到这样的出错信息:
    telnet: Unable to connect to remote host: Connection refused
    就说明远程服务器上没有运行SSH服务软件。
    端口转发使用这样的命令语法:
    ssh -f [username@remote host] -L [local port]:[full name of remote host]:[remote port] [some command]
    你不仅可以转发多个端口而且可以在"~/.ssh/config"文件中用"LocalForward"设置经常使用的一些转发端口。

    为POP加上"加密通道"

    你可以用POP协议从服务器上取email。为POP加上"加密通道"可以防止POP的密码被网络监听器(sniffer)监听到。还有一个好处就是SSH的压缩方式可以让邮件传输得更快。
    假定你在pop.foobar.com上有一个POP帐号,你的用户名是"bilbo"你的POP口令是"topsecret"。用来建立SSH"加密通道"的命令是:
    ssh -f -C bilbo@pop.foobar.com -L 1234:pop.foobar.com:110 sleep 5
    (如果要测试,可以把"sleep"的值加到500)。运行这个命令之后会提示你输入POP口令:
    bilbo@pop.foobar.com's password:
    输入口令之后就可以用"telnet"连接到本地的转发端口了。
    telnet localhost 1234
    你会收到远程mail服务器的"READY"消息。
    当然,这个方法要求你手工输入所有的POP命令,这是很不方便的。可以用Fetchmail(参考how to configure Fetchmail)。Secure POP via SSH mini-HOWTO、man fetchmail和在"/usr/doc/fetchmail-[…]"目录下的Fetchmail的FAQ都提供了一些具体的例子。
    请注意IMAP协议使用的是不同的端口:IMAP v2的端口号为143而IMAP v3的端口号为220。

    为X加上"加密通道"

    如果你打算在本地计算机上运行远程SSH服务器上的X程序,那么登录到远程的计算机上,创建一个名为"~/.ssh/environment"的文件并加上这一行:
    XAUTHORITY=/home/[remote user name]/.Xauthority
    (如果在远程主机上你的家目录下不存在".Xauthority"这个文件,那么当用SSH登录的时候就会自动创建)。
    比如启动一个X程序(xterm)可以这个命令:
    ssh -f -X -l [remote user name] [remote machine] xterm
    这将在远程运行xterm这个程序。其它的X程序也是用相同的方法。

    为linuxconf加上"加密通道"

    Linuxconf(http://www.solucorp.qc.ca/linuxconf/)是Linux的配置工具,它支持远程管理。Linuxconf的FAQ重说明了如何通过SSH使用linuxconf:
    其命令为:
    remadmin --exec [link_command] linuxconf --guiproto
    如果你想在两台计算机之间用加密的方式传送信息,那么最好用ssh。命令是:
    remadmin --exec ssh -l [account] linuxconf --guiproto
    这是非常有效的而且运行用图形界面管理计算机。
    这种方法需要在客户端安装linuxconf。其它的方法还有直接登录到服务器上用"X11Forwarding"或字符界面运行linuxconf。

    为Webmin加上"加密通道"

    Webmin(http://www.webmin.com/webmin/)是一个新的基于浏览器的配置工具。它运行在1000端口。你可以用SSH的"端口转发"对它进行加密:
    ssh -f -l [remote user name] [remote host] -L 1234:[remote host]:10000 tail -f /etc/motd
    把浏览器指向
    http://localhost:1234

    转载自:http://fanqiang.chinaunix.net/safe/program/2005-03-24/3011.shtml

  • Tag:

    题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。不允许用java提供的类库。

    例如输入I am a student.,则输出student. a am I
    分析:由于本题需要翻转句子,我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。
    还是以上面的输入为例子。翻转I am a student.中所有字符得到.tneduts a ma I,再翻转每个单词中字符的顺序得到students. a am I,正是符合要求的输出。

    private void reverse(char[] src,int start,int end){

            while (start<end){

                char temp = src[start];

                src[start] = src[end];

                src[end] = temp;

                start++;

                end--;

            }

        }

            private void reverseWord(char[] centense) {

                int i = 0;

                int start = 0;

                while (i<centense.length){

                    if(centense[i]!=' '){

                              i++;

                    }

                    else{

                        reverse(centense,start,i);

                        start = i+1;

                    }

                }

            }

     

        @Test

        public void should_reverse_string(){

            char[] centense = {'i',' ','l','o','v','e',' ','y','o','u'};

            reverse(centense,0,centense.length-1);

            reverseWord(centense);

            System.out.print(centense);

        }

  •  

          最近从一个做了16个月的项目上roll off,换到了一个‘新’团队。其实这个项目也做了1年左右了,对于我来说虽然是全新的环境,全新的技术,但是对于在这个团队中的老成员而言,也有种对项目结束望眼欲穿的心情。其实说实话,项目做久了,多少都有自己的特点、惯性和问题。只是由于组员,客户的特性不同,而略有不同。但尤其是是在更加注重人的敏捷团队中,由于人的原因所造成的问题更加引人注目。

          其实大到国家,小到公司,团队甚至家庭,都采取着或中央集权,或民主自治的形式进行管理和沟通。孰好孰坏,每个人心里都有自己的想法(你懂的)。但这种组织方式放到一个真正以人为本的团队,问题就会更加突出。以把我亲身经历的2个项目为例。

    项目A----团队成员:

                        资深架构师1

                         Tec Lead 1

                         开发人员7

                         PM 1

        层级结构是按照技术决策权来的,我想这种结构在大多数团队是比较普遍的一种组织方式。之所以大家喜欢采用这种方式,其实原因很简单:便于管理,因为有权威人士压阵,大家不会群龙无首;分工不同,大家可以各司其职,从而可以提高工作效率。但也存在很多问题,大家如果也经历过这种项目或组织(你懂的),肯定可以列举出很多点来,例如:决策风险性高,毕竟大家都是凡人,没有人一辈子都不犯错误,但这个错误一旦是处于决策顶端的架构师犯得,那影响是很多的;团队士气和声音会受到打压,没有了发言权,或没有倾听者,对于每个团队成员来说,无疑会带来巨大的挫败感,进而影响工作热情和效率。而在我们的团队中,就存在由此引发的种种问题,最后的结果就是经历了9个月才完成真正的release。而这九个月中除了架构师忙的昼夜无眠外,其他人都处于游离状,大家除了觉得无名的挫败感外,就是有劲没处使。主要原因在于,中央集权的过于严重,早期开发中大家提出的问题和疑虑,被无情的受到了打压;中期问题凸显后,大家纷纷摩拳擦掌想去解决,但由于个人能力,以及前期对问题根本的认识不足,个别情况没有处理好,让架构师失去了信任,于是架构师把问题都大包大揽,决定自己解决;后期就是一大堆的问题大家都无能为力,而架构师时间和精力有限,成为了所以问题的瓶颈。

    项目B-------团队成员:

                         Tec Lead 1名,5名开发人员

        技术决策完全民主,每个人都享有同等的发言权。这或许是很多人向往的团队组织方式,因为你可以有于老大同样的话语权。但如果大家都可以决定自己的薪水,结果会是如何呢?。而更糟的是,每个人都承担相同的责任,所以你不会让自己去承担别人决策的责任,也绝不会放弃自己的权利。在一个开发团队中,情况也非常让人吃惊。我们会为了一个表名到底叫什么,讨论半个小时。为完成一个需求所采用那种技术架构争论1个小时都没有任何结果,因为大家都在自己的假设性,做出正确的判断,可有于每种推断是完全有理有据的,没有人可以说服对方。最后的结果是,遇到每个问题,大家都不得不讨论很久,从而导致大家渐渐对讨论越来越厌烦,甚至不想再参加这种无休止的讨论。因为这个过程不但降低了工作效率,还总是没有太好的成果。但好消息是,没有人会成为项目的瓶颈,大家可以有自己的很多建议和想法。结果如何还有等到我们真正release了,才好告诉大家。

        但我要说的是,这两种情况无疑都暴露了团队的沟通问题。人的问题永远都是一个团队最重要,最难解决的问题,而一切这类问题都可以归结为沟通问题。这或许就是敏捷宣言中为什么把“个体和交互”放在一起的原因的。而针对有效沟通存在的方法有很多种,其中DISC模型是我看到的很实用的一种方式。DISC代表着4个角色(Dominator, Influencer, Supporter, Critical Thinker),他们在团队中承担不同的责任。Dominator 有较高的威望和洞察力,并带领大家达成既定的目标;Influencer 喜欢说出自己的想法和疑问,从而引起大家的思考,同时可以接纳别人的想法;Supporter 是个低调的Team player,具有很好的聆听能力,目的在于成为最后的团队成员。Critical Thinker 是个思维缜密的完美主义者,关注并分析问题的所有细节。当然,在讨论过程中,每个人可能在不同的时间点担任不同的角色。但如果讨论过程中,一直存在某个角色的缺失,那么讨论的效率和效果就大大折扣,不信的话,我们自己试验一下。。。

     

  • Tag:

    .     进入新的项目组,发现这个项目组几乎没有什么Agile的痕迹。这让我很惊讶。。。没有Pair,没有Code review,也没有人关心CI是什么颜色。这一切的理由就是要快速上线,所以什么其他的东西都不重要。。。不知道其他人是什么反应,我反正是被震到了。毕竟这个Team里一半的人都是公司的老员工,甚至有元老级的人。

                初来乍到,我们也不敢轻举妄动,毕竟我们还是新Member。但是,作为一个“局外人”,我们有很多优势,比如有义务主动给大家带来"新鲜血液"。所以我们就一点点说服大家采用我们之前屡试不爽的小实践:

    1. 分离开发机器和个人机器。就是开发时,不可以把自己的笔记本放在旁边。换言之就是,干活的只能一心干活,不会三心二意。同时,pair的彼此也感受到了应有的尊重。试想一下,如果你在埋头干活,你的Pair在哪里聊天,或者网上购物,你会是什么心情呢?但是万事有利弊,规定的太死板也让人很不爽。例如要在自己电脑上考东西,或者要给出差的机器装环境,就要来回跑。
    2. Tasking。上过OObootcamp的同学都应该对tasking这件看似不太重要的活动有印象。但我但我要说的是,tasking真的是写代码的核心。在着手写代码前,尤其是面对比较复杂的需求,tasking不但可以让我们思路清晰,并保证2个人统一思路,同时还可以发现一些架构中的漏洞,而且在 switch pair的 时候,可以方便的进行knowledge传递。这项实践尤其是在做功能复杂的需求时,更能体现它的价值。
    3. 15分钟session。15分钟你可以做什么,可能是打个水的时间,同时碰到了同事,闲聊几句;或者是吃水果的时间。但是如果我们把吃水果的时间,把一个Team的人组织在一起,一起做个session,技术相关的或者无关的,不但没有浪费太多工作时间,同时可以增长大家见识,提高大家士气,同时还可以让大家放松心情,增进大家感情。
  • 重构与否? - [Tec]2010-12-28

    Tag: 重构

          今天花了一整天的时间,在做javascript的重构,并着手给重构的代码加unit test。说实话,半路萌生过想放弃的念头,但是最终还是坚持下来了。为什么想放弃呢,主要有以下几个原因:

     

    1. 我的pair认为这个“遗留的”javascript,很难测,如果从这个地方入手,第一次引入javascript unit test,难度会很大。。。我虽然可以理解他的心情,但是还是坚持说服他继续做下去,原因很简单,就是因为所有的js代码都还裸奔着,这样迟早得出大事,所以,我们死也要给他加上测试。
    2. 确实,对于现有的琳琅满目的js unit test框架,不太熟,所以选择多了,反倒是坏事。大家讨论了半天,也没有达成一致。。。讨论的时间过长,降低了大家行动的士气。
    3. 一般的IDE对js code没有很好的重构支持,导致重构过程,很多都是拷贝/黏贴。。。我对这种完全原生态的重构方式,还确实不放心。结果也是证明了,除了一些bug。
    4. 由于这些bug的引入,导致,我对这次重构的影响有了更多的担心,比较这是很核心的部分,如果出了问题,将会后患无穷。。。这也是我坚持要加unit test的主要原因。
    5. 对项目的进度有影响。话说如果不进行这次重构,那么我们今天可以做更多的新功能,而进行了这次重构,除了让我们自己心里更舒服/安心,客户是非但不会买账,还会让这个迭代的velocity也很有所下降。。。假如我是PM,或许我会有所妥协。不过,还好我不是。当然,我还是尽快去做好他。
          截止到现在,重构还在进行中,但是令我欣慰的是,这次重构,不但让代码更加清晰了,重用性提高了,还利用我们的unit test发现了2个连QA都没有发现的,已经存在系统已久的bug。
          所以,以后如果还做类似的重构,我们还是首先要保证有单元测试。否则,结果可能就不一样了。

     

  • OO Design in Agile - [Agile]2010-12-26

    Tag: design

            在我们平时的软件开发中,是否有遇到过如下情况:

    • 每次增加新更能,或者改bug,总有牵一发而动全身的感觉,导致开发成本越来越高。
    • 对代码的微小改动,竟然会引起业务不相干的功能被破坏。
    • 重复的代码和劳动,比比皆是。
    •  同一个Bug,或者同类的bug反复出现.
    • 开发人员的流失,导致以前的代码成为没人敢碰的黑洞。

            而所有的这些问题,对于整个团队的危害,可能是导致大家士气低落,越来越多的人想离开这个项目;而对已一个公司而言,无疑是一个定时炸弹,随时都可能毁掉整个公司。

            如何解决/避免这个问题?有人说要提高代码质量,有人说要改进开发过程。那么敏捷软件开发和设计,是很好的一个解决方案。

            敏捷软件设计采用的是简单设计方法,但不是没有设计,在简单设计中,我们希望代码先能工作,然后再进行小步重构。在重构的过程中,有很好的设计原则来指导我们将代码变为可维护,可复用的健壮代码。他们分别是:

    1)      单一职责原则

               a)      即:仅有一个引起他变化的原因

               b)      实现原则:从业务的角度上,在同一层的对象间进行分割;分割的粒度,要权衡对象的复杂度和对象间的通信代价

               c)       侧重点:解决对象间的分层和职责划分问题

    2)      开放-封闭原则

               a)      即:对象对扩展是开放的,对更改是封闭的

               b)      实现原则:对于代码中,频繁变化的部分抽象出pluggable的模式,例如strategy模式和template模式。但是,这些代码模式应该是重构出来的,不是第一次编码设计出来的。因为,过早的抽象,在后期变化部分不同时,还有重新抽象,导致抽象对象的维护和重构成本变大。

               c)       侧重点:解决对象的抽象和多态,他也是OO Design的核心所在。

    3)      Liskov替换原则

              a)      即:子类型必须能代替他的基类型

              b)      实现原则:子类不删除/覆盖父类的功能。当出现如下情况class A{ function1(), function2()}, class B:A{ function1(), function3()}。我们可以采用提出公共部分的方式,避免这种情况:class C{ function1()}, class A:C{ function2()}, class B:C{ function3()}

              c)       侧重点:解决对象的继承和组合关系,他是开放-封闭原则实现的基础。

    4)      依赖倒置原则

              a)      即:高层模块不应该依赖于底层模块;抽象不应该依赖于细节

              b)      实现原则:分层的框架设计,例如,高层模块要独立于底层模块,最好是降低模块间的耦合性;分离抽象和具体实现细节,从而依赖于接口和抽象类,例如,如果要使用一个有抽象基类的类,可以持有他的基类(例如,在需要引用和继承时)。如果使用一个变动不大,且没有派生对象的类,损害也不大。表动,应用和模块前

              c)       侧重点:是针对框架(framwork)设计的核心原则。

    5)      接口隔离原则

              a)      即:实现类不应实现接口中定义的不用方法。

              b)      实现原则:把胖类的接口分解为多个特定于客户程序的接口,再多重继承这些接口,或者使用委托分离接口。

              c)       侧重点:解决胖接口的缺点,即不具备内聚特性的接口。

  • CI是一种态度 - [Agile]2010-12-20

    Tag: CI

          每个人对敏捷的理解都不尽相同,有人认为敏捷的核心就是快速反馈,有人认为敏捷的核心是无障碍的沟通。但无可厚非的是CI是敏捷实践中,最能体现敏捷特性的活动。因为CI可以以最直观的方式,最快的速度得到反馈。

          CI来源于XP的12个实践之一,可以说是融汇贯通其他实践的一个利器,估计很多项目都可以做到这些实践,比如:使用大家都有更改权限的subversion工具管理代码;自动化的构建,测试,以及部署;在接近生产环境中进行测试;让每个人都能轻易获得最新的可执行文件,尤其是客户和测试人员。最重要是,可以可视化build的状态,让Team中的每个人都可以清晰的看到Dev的更改,以便安排自己的工作进度,可以说他是一种最有效,且直观的沟通方式。

          但是即使我们有了这一套CI实践,而不没有坚定不移的维护他,结果当然是截然不同的。例如有的Team,在build已经失败的情况下,还不停地check in code,并且没有人有时间修复一下;还有的测试覆盖率极低,没有达到很好的自动化测试的效果,且测试环境和生产环境相处甚远;更有甚者,大部分开发人员多代码没有所有的操作权限,等等。其实,这个时候的CI就形同虚设了。所以,与其说CI是一套实现活动/或者是一套软件系统,倒不是说是一种维持软件开发过程时刻保持可运行,整洁的态度。如果有了这种态度,我想CI可以做的实践还可以更多一些吧。

          态度决定一切。


    备注:XP的12个实践包括以下内容:

    • User stories (planning)
    • Small releases (building blocks)
    • Metaphor (standardized naming schemes)

    • Collective ownership
    • Coding standard
    • Simple design
    • Refactoring
    • Testing (TDD)
    • Pair programming
    • Continuous integration
    • 40-hour workweek
    • On-site customer     
  • 我们的敌人BA - [Agile]2010-12-18

    Tag: BA

          作为DEV,我对BA有一些看法。尤其是最近和我们Team的BA进行了几次狂风暴雨办的争论,而且是我想刻意表现的nice一点,但是最后还是没有把持住。。。罪过,罪过。

          我突然想到一个发生在身边的故事:我让哥哥给我一个锤子,他翻箱倒柜,找了半天也么有找到。无奈之下,跑来问我,你要锤子干什么。我说:“我要砸核桃吃”。他很快给了我一个核桃夹。。。同时还给了我一个小垃圾桶,以免我把核桃皮弄得哪里都是。。

          我想,如果我是客户,哥哥作为BA。经过几番周折,他从一个不太称职的BA,被逼成了一个还不错的BA,我做为客户,还是比较满意的。

         其实,作为客户,他对乙方的要求的详细程度和对软件的认识都是参差不齐。有的直接给乙方说我需要这个Button,我需要这个表格。但是有的BA没有询问并分析用户需求的真正原因,就原封不动的把需求搬过来,让Team的人全力以赴。但是有时这个Button/表格不能真正的解决客户的问题,结果就是大家伙很费力的做了一个没有任何价值的垃圾。而这种没有价值的需求如果可以在需求分析阶段就能经过过滤/改良,就无形中给Team带了更高的velocity。看看,BA是多么重要的角色啊。

        像故事中的一样,不但能根据客户的真正价值设计需求,并考虑其他相关的更多细节,那客户应该会感到非常贴心,满意。(哈哈,BA和客户的关系有点像男女朋友的关系)。BA如果能把客户当成自己的初恋女友一样体贴,呵护,那估计就没有拿不下的项目了。同时,DEV们即使再苦再累,也心甘情愿吧。

  •       我们整体喊着我们要TDD,要体面的测试覆盖率,但是写测试的过程中,遇到过的问题也是种类繁多,有的也是刻骨铭心。

     

    • TDD不仅仅是果,也是因。有时候我们为了TDD而TDD,而自己忘记了为什么要这样TDD。但是TDD也是一个很好的驱动实现的途径。当我们对要实现的功能没有完全清晰的时候,当我们迷失在漫漫实现之路上的时候,单元测试是一个让我们一步一步前进的有力强心剂
    • 测试难,可能是了我们代码结构的问题。上代码:

          class Television{

              public void display(){

                 getDigtalChanel()

              }

              private Chanel getDigtalChanel(){}

          }

    getDigtalChanel()有自己负责的计算逻辑,但是他是private的,如何测试他呢?完全用过display()来测试?还是把getDigtalChanel()改成public呢?

    其实这个时候,我们的感到不舒服的时候,就是重构的最佳时期。Television这个对象需不需要负责接受信号,他的职责是不是太多了?答案是显然的。我们可以把getDigtalChanel()拿出去,放大信号接受对象里。这样对象的职责和关系是不是就更加清晰了,测试也很容易做了。

    • 不能因为测试改动我们的代码。用代码说明一下:

            public getRate(x,y){

                  return x/y

             }

     

            Test

             publish should_caculate_rate_when_coords_not_equals(){

              def rate = getRate(10/5)

              Assert.equals(2,rate)

             }

    这是我们的初始实现,但是测试的时候发现rate和2怎样都不相等,原因是rate的类型不是int。急于让测试通过的同学可能会把代码改成:

              public getRate(x,y){

                   return (int)x/y

               }

    哈,测试通过了,但是bug也出现了。原因是强转类型为int会让计算的结果去整,那么计算的精度就大大折扣了。。所以,不用轻易为了测试改动代码,出发是测试过程中发现的bug.

    • 测试真正的代码,而不是mock/stub。如果你可以测试真正的代码,无论是重构代码结构,还是做大量的数据准备,我们都不遗余力的测试它,而且同同时可以达到很好测试覆盖率和测试效果。而Mock/stub是我认为最形式化的测试方式。虽然可以达到很快完成测试的效果,但是事倍功半。

     

  • Tag:

          从业2年半,虽然经过了大大小小的几个项目,只有当前的这个项目让我对职业道德有了更多的体会。不管我们是初出茅庐,还是经验丰富,怎样才是一个有职业道德的程序员?才能对得起客户付给我们的报酬。

    1. 理解需求背后的用户价值
    2. 坚定不移的坚持我们的实践和约定,不惜一切代价
    3. 熟悉代码库中的每一行代码
    4. 提高测试质量和覆盖率
    5. 提高每个成员的工作效率,也是我们的分内工作
    6. 打通瓶颈,无论是谁造成的瓶颈
    7. 不相信任何大牛的保票,实践是检验真理的唯一标准
    8. 没有被大家接受并正确实施的架构/技术,不是好架构/技术
    9. QA,Dev是一家人。Dev是最好的测试人员,帮助QA就是帮助自己
    10. BA是我们的敌人,我们要在需求完成前,对他展开全面的轰炸,直到炸光他的每一个存有用户价值的细胞。
    11. PM是我们的最得力的后勤,我们永远的朋友。
    12. 保障工作激情。没有激情的时候,给大家创作激情

     

  • Powerful Bash - [Tec]2010-07-08

    Tag:

    GNU is meant to be free and unrestricted by other distributors. Any programmer is allowed to have access to the code and projects created using GNU.

    To make this happen, the GNU Project began working on an operating system called GNU ("GNU" is a recursive acronym that stands for "GNU's Not Unix"). This goal of making a free software operating system was achieved in 1992 when the last gap in the GNU system, a kernel, was filled by a third-party Unix-like kernel called "Linux" being released as Free Software, under version 2 of the GNU GPL.

    Once the kernel and the compiler were finished GNU was able to be used for program development. The main goal was to create many other applications to be like the Unix system. GNU was able to run Unix programs but was not identical to it. GNU incorporated longer file names, file version numbers, and a crashproof file system. The GNU Manifesto was written to gain support and participation from others for the project. Programmers were encouraged to take part in any aspect of the project that interested them.

    Bash is a free software Unix shell written for the GNU Project. Its name is an acronym which stands for Bourne-again shell.

    Bash is a POSIX shell with a number of extensions. It is the shell for the GNU operating system from the GNU Project. It can be run on most Unix-like operating systems.

    http://ss64.com/bash/

  • Tag: apache

    Apache关于request/resonse header 设置的问题很多,现就其中2个小问题,说明一下。

    1. 不同浏览器对于download框的显示有所不同,有的显示正常的download对话框,有的则直接下载,并打开。

    解决方法:在Apache server的vhosts.conf文件中,设置相应的

    <LocationMatch "/content/.*\.download\..*">

       Header set Content-Disposition "attachement"

    </LocationMatch>

     

    2. 不同的浏览器中,下载不同的CAD文件,默认的保存格式都是.ps / .zip...根据默认,Apache 通过检查文件的扩展名来决定与每个文件一起发送的媒体类型。扩展名类型映射存储于 httpd/conf 目录(通常是类似 /usr/httpd/conf 或 /etc/httpd/conf 的目录)下的 mime.types 文件中,里面定义了对于很多文件的content-type。

    默认情况下.ai, .esp, .ps, .psd文件的content-type为Application/postscript, 所以只要对每种CAD文件做相应的设置即可:

    image/ai   ai

    image/esp  esp

     

    遇到Apache问题,看官方文档才是王道。

     

  • 还是经验不足啊,对session的理解不足。出现了这个错误,后来查了一下,

    在调用session_destroy()之前,需要调用 session_start();

    来告诉系统你当前是有session的。然后再去关闭,呵呵。郁闷啦,这个问题。。。。

  • 转载自:http://tekkenvs11.javaeye.com/blog/398662,感谢。

    CSS ‘width’ 指的是标准CSS中所指的width的宽度,在firefox,opera等中的宽度就是这个宽度。它只包含容器中内容的宽度。

    而Internet Explorer ‘width’则是指整个容器的宽度,包括内容,padding ,border。

    所谓的CSS的宽度的加法减法就指这里不同浏览器对width解析得到的不同结果。

    Firefox中是加法:容器占的宽度=内容宽度+padding宽度+border宽度

    IE中是减法:内容宽度=您定义的容器宽度(Internet Explorer ‘width’)-padding宽度-border宽度

    大家区分的时候重点是分清:内容宽度和容器所占宽度这两个的不同

    由于以上差别的存在,必然造成定义的一个容器宽度在不同浏览器中显示出不同的效果来。解决办法主要有两种:

    一种是写hack
    一种是采取在当前容器中再增加一个div的方法来解决。

    写hack:
    给不同的浏览器写一个不同的width: div.aa{width:100px; *width:120px;}Firefox等浏览器只能认出前一个width来,因此它会认为这个div容器的宽度是100px,而IE6等浏览器则两个都能认出来,但是根据优先级,写在后面的会被采纳,因此IE6会认为这个div容器的宽度是120px;

    增加一个div或者其它容器的方法:
    div结构是:
    <div class=”aa”><div>内容放在这里</div></div>
    CSS代码是:
    .aa{width:120px;}
    .aa div{padding:10px;}
    将padding border与width分开来写,分到不同的div里面,既不用做加法,也不用做减法,外面的div直接采用我们给它指定的宽度

  • about code review - [Tec]2010-06-18

    Tag:

    最近看了很多面试的代码,有几点大家都多少会出现的问题,总结一下:

    1. 需不需要getter and setter

    经常看到这样的code:

    public class Position {
        private int x;
        private int y;
        public Position(int x, int y) {
            this.x = x < 0 ? 0 : x;
            this.y = y < 0 ? 0 : y;
        }
        public int getX() {
            return x;
        }
        public void setX(int x) {
            this.x = x;
        }
        public int getY() {
            return y;
        }
        public void setY(int y) {
            this.y = y;
        }
    }

    我不知道笔者对于getter and setter的看法是如何的,但是如果必须有public getter and setter, 那么和public field x,有什么区别呢,同时那种所谓java风格的code,还会带来多余的代码,预期这样,何不简单为之呢?

    public class Position {
        public int x;
        public int y;
        public Position(int x, int y) {
            this.x = x < 0 ? 0 : x;
            this.y = y < 0 ? 0 : y;
        }

    }

    2. 过度设计和代码灵活

    很多人看到题目/需求,会假象很多潜在的边界情况,但是要适可而止,如果假设的太多可能就过度设计了。但是过度设计和代码灵活是不相违背的,因为作为程序员,在满足当前需求的情况下,让对象之间关系更加明确和清晰,是基本素质,如果对象之间关系过于亲密,或者功能重复,会给后期功能的增加和改动带来不必要的麻烦。

  • 假如从来一次2010-04-18

    Tag:

          世上没有时光倒流机,但是我只是做个假设,以免悲剧重现

          8月,项目开始的前一周,Tec Lead 和 architecture specialist给了我们一份技术名词的List,需要我们依次研究。我问了他们:为什么要用这个技术***,回答是:Day CQ 基于这种技术。为什么用 Day CQ,以前的项目不是为此吃了很多苦头么? 回答是:客户已经买了Day CQ...

         其实我应该问,咱么有没有相关的技术Spike,Day CQ真的适用于这个项目需求么?

         可惜我没有问,当然也就没有这个Spike....

     

     

  • - [Thoughts]2010-04-18

    Tag:

    宅:作为一个多义词,在不要的场合下,赋予了很多不同的含义。

     

          平时我喜欢在家宅着,看书/写代码/看电影,哥哥说我很无聊,可不可以找点有趣的玩。但是我觉得相比跑出去,百无聊赖的逛街,或者看一些貌似也没什么特别的风景外,还是在家做这些让自己觉得有意思的事情,更让自己兴奋。。

     

          出差到了异国他乡,我还是喜欢宅在家里做这些让自己觉得很充实,很开心的时候,总会招来同事不解和异样的眼神。因为大家都觉得,出来异乡,参观风景是头等大事。我也根据他们的建议,去过一些景点,但是总觉看这些景点和风景的时候,少了很多东西,有时候甚至觉得自己好孤单啊,内心的孤单。因为看到风景和周围情侣的时候,总让我想起远在北京的哥哥。

     

          不管他们怎么看,怎么说吧,自己的做自己喜欢做的事情,对大家没有伤害,对自己也是一种善待,何乐而不为之呢?很喜欢这个apartment的装修风格,简单,实用,干净,同事也很安静。对于我来说,实在是宅的最佳环境。希望喜欢宅的人,和喜欢到处走走的人,各得其乐。

     

     

     

  • 当在命令行下调用php去执行一个.php文件时。出现undefined function mysql_connect 错误。而通过web访问无此问题存在。那么可能的原因是。命令调用的php版本不支持对应的mysql_connect 函数。

    可通过php -v 查看php程序版本是否正确。

    在一台web服务器上管理员可能安装了多个版本的php,或者因为升级,并没有删除所有老的php程序,造成该问题。

    一般情况下,最新的程序版本应该位于/usr/local/bin/目录下。

  • Be professional - [Thoughts]2010-01-31

    Tag:

    作为一个软件咨询公司的开发人员,Senior的人总是教育我们说,要专业

    比如,showcase的时候,要做好充分的准备,不要出大的差错;见客户要选好dress code;给别人讲述敏捷,要先了解对方,才好对症下药,等等

    说实话,我们只是尽量去模仿别人做的好像更加专业,但是,并没有感觉到这样会有什么好处。

    但是,自己亲身经历过一次专业的服务以后,就深刻体会到了专业的含义。

     

    自从留了长发,每次去理发馆,都是不同理发师给你相同的建议:烫了吧/染了吧/做护理吧。。。

    貌似是为了让你变得更加漂亮,但是他们都没能打动我,因为他们不知道,我对于头发要求只是健康+好打理,因为我是个十足的懒女人(没化过妆,不喜欢逛街,对高跟鞋更是十分恐惧)

    所以,等我在一家理发馆饱受推销之苦以后,就开始寻找另一家。今天,终于有找到一家新的,进门我就说:我只是剪发,如果间的还可以的话,我就办卡。

    洗头,坐下,很快,,一个穿着整齐的男理发师,过来打招呼,头型是我见到的理发师里,最简单的(小平头),提着一个很大的工具箱。。。我心里马上觉得,还不错哦,不像以前,都是一些头型很奇怪的人。

    之后,便是上剪,下剪,左剪,右剪,伴随期间的是,给我的一些中肯的询问和建议,例如这么短可以么?从那边分?可以吧左右发根垫一下。。。

    最后,我办了一张卡。很高兴的

    剪得头型,说实话,没有什么新花样。但是,让我觉得,我下次还可以去他家

     

     

     

  • Tag:

    很小的时候,(估计小学没毕业)姥姥逗我玩,

    问我:你出嫁的时候,我去你婆婆家,记得给我做好吃的啊

    我回答,我还没有打算结婚呢(晕啊,小学没有毕业的人一般都么这个打算)

    姥姥问我:你什么时候打算一下啊

    我说:等我研究生了,再打算。。。

     

    本科毕业计算机专业,但是毕业时觉得自己对代码还一无所知,于是,考了研

    终于,考试研究生了,也同时找到了自己现在的老公

    还是没有结婚的计划,因为还不知道自己如何立命。

     

    参加工作的第一年,似乎还是对代码有些恐惧。。。,身边的大牛好多啊。

    终于在参加了WGSN项目组后,对代码产生了特殊的情感

    觉得一辈子就写代码,也很幸福

     

    昨天,和邻居的女孩子们一起蒸桑拿,聊天

    说到了工作,孩子,家庭

    有人说:做IT的也是个青春饭,年纪大了公司就不要了

    我也不知道她说是不是她的切身体验,还是道听途说

    但是,我们要反驳

    我心想,如果国内不要我这种一直写代码,写到老太太的人

    我就去国外

    起码,我见过国外的同时70多岁还在写的人,呵呵

     

    人,活着纯粹点,多好啊

     

  • - [Thoughts]2010-01-24

    Tag:

    人常说:己所不欲,勿施于人

    但是,我常常把自己认为很好,很珍贵的东西分享给别人,希望别人也得到同样的乐趣,但是屡屡碰壁。

    于是,得出:己所之欲,施与人乎?

    不一定

    这要看自己给予的方式和技巧,但所有的一切,都要看对方的态度和想法。否则,适得其反

  • Apache ReWrite模块提供了强大的URL操作功能。可以满足的负责的URL处理需求。本人也是新手,关于Apache ReWrit,研究一下再行补充。

     

    应用一:匹配相似的url。如 a.js = a.1.js 即当访问a.*.js时Apache会将URL重写为a.js。需要避免因为页面缓存原因导致功能异常的情况,可以使用这种方法。其中*的内容可以使用任意的服务器端脚本进行生成,如生成随机数、时间戳等等。

    示例:

    RewriteCond %{REQUEST_URI} (.*)\.\d*\.js$ RewriteRule ^.*$ %1.js [L]

  • 1.使用面向对象编程时,如$this->xxxx,注意在$this之后的内容前面不用写$符号。否则会出现:Cannot access empty property错误。因为找不到$xxxx的属性。当然如果属性名本身就是$xxxx也是可以的吧。呵呵

     

  • jquery选择器的使用看似简单,其实还是有些难度的。最好的学习方式就是查看jquery文档或手册。

    选择(select)下拉框选中的值:

    $('select option:selected').val();这是新版本的写法。$('select [selected]').val();这种写法在firefox中可能存在bug,导致取不到正确的值。

  • 关于提问 - [Thoughts]2009-12-03

    Tag:

     有人问我设计UI交互的问题,我说了一个方案,他说:不,这不是我想要的

     我问他你想要什么,他说:如果我知道我想要什么,我就不问你了

     但是如果你连你自己想要什么都不清楚,我怎么能给你想要的呢?

    或者说,你怎么知道我说的不是你想要的。

     

    看似很纠结的问答,实际上存在很大的提问技巧问题。

     

    很多时候,我们确实因为对自己面临问题如何解决,存在很多无知,

    但是如果能有,合适的提问技巧,就可以打开自己的思路。

    比如,不直接切入问题本身,探讨下解决问题的思路,或者,询问下对方是否遇到过××问题。等等

  • zz:http://blog.csdn.net/fredtaylor/archive/2009/08/31/4504665.aspx

     

    DOM方法:

    父窗口操作其下的IFRAME:window.frames["iframeName"].document

    或者直接写frames["iframeName"].document

    IFRAME操作父窗口: window.parent.document

      或者直接写parent.document

     

    jquery方法:

    在父窗口中操作 其下IFRAME中的元素: $(window.frames["iframeName"].document).find(”:text”);

    在IFRAME中操作 选中父窗口中的所有输入框$(window.parent.document).find(”:text”);

     

    使用find可以找到自己想要的东东。

    想要找到同级的iframe,可以用$(parent.frames["iframeName"]).find("xxxxxx")

     

    细心的朋友一下就能理解,原理其实很简单,就是用到了$(DOM对象)转换成jquery对象。

     

  • Tag: Ubuntu

    先写点常用的command:

    apt-get:
    debian系统的软件包管理程序(其图形化前端就是大名鼎鼎的新立得了):
    update        —-与你的软件源(在/etc/apt/sources.list中列出)更新软件包列表,换源后需要执行
    upgrade        —-根据update得到的源软件库与本地已经安装的对比,(如果需要升级就)全部升级
    install        —-安装软件包(可以使用tab补全软件包的名字,比较方便)
    remove        —-卸载软件包
    purge        —-卸载软件包,同时删除该软件的配置文件
    source        —-从源里下载软件包的源码到当前目录(执行此命令的目录)并解压(除非指定–download-only参数)
    该地址由/etc/apt/sources.list中的 deb-src 行指定
    check        —-用来(自动)修复(已装)软件包之间的依赖关系
    clean        —-清除/var/cache/apt/archives/包括其子目录partial/下的所有软件包缓存

    cat:
    把(一个或多个)文件内容(连接)显示到标准输出
    当文本文件很小,而且你只是想看下,并不打算用gedit或者vim之类编辑器编辑的时候,可以cat一下

    cd:
    切换当前工作目录
    最常用参数:
    .        —-切换到当前目录(貌似没有什么意义)(.这个目录可以通过ls -a看到)
    ..        —-切换到上层目录
    ~        —-回到家目录(/home/你的登录名/)

    chmod:
    改变文件的权限位
    linux文件系统的权限位有两种表示方法,要是详细说下,非得累死老鼠不可=.=,所以只说8进制数表示:)
    简要介绍下:ls -l可以显示出文件的权限,比如(-rwxr-xr–),代表了三种用户的权限
    第一个rwx,代表文件所有者的权限,即(读,写,执行),用二进制表示为111,代表八进制中的4+2+1=7
    第二个r-x,代表文件所有者同一用户组其他用户的权限,即(读, ,执行),用二进制表示为101,代表八进制中的5=4+0+1
    第三个r–,代表其他用户的权限,即(读, , ),二进制表示为100,代表八进制的4=4+0+0
    所以这个文件的权限位为754
    这也就是chmod的用法,例如chmod 751 myfile #将该文件权限设定为rwxr-x–x
    最常用参数:
    -v        —-列出当前正在执行的步骤
    -R        —-递归式,即改变非空目录下的一切为指定权限
    cp:
    拷贝文件和目录
    最常用参数:
    -b        —-为每个已经存在的目的文件作个备份
    -d        —-遇到软链接时不拷贝软链接所指向的文件;拷贝时保留links属性(链接数)
    -p        —-保留文件的访问权限,所有者,和时间戳
    -R和-r    —-递归式拷贝(cp过程遇到非空目录才有效),即拷贝目录,子目录,子目录的子目录…..
    -a        —-作用同-dpR
    -s        —-并不真的做拷贝,而只是为每个文件作软链接(符号链接)
    -u        —-同下面 mv 的-u参数

    head, tail
    就像这两个名字,一个显示文件头部,一个显示尾部
    最常用参数:
    -n        —-指定输出的(头部或尾部)行数, 当没有此参数时,默认显示10行

    ifconfig:
    配置网卡
    最常用参数:
    没有参数        —-列出当前活动网卡的状态
    -a            —-列出所有网卡的状态
    interface    —-指定网卡名称比如eth0
    up            —-唤醒该网卡
    down        —-关闭该网卡
    arp,mtu,netmask addr,…等等很多参数 =.=

    ln:
    为文件建立链接
    linux的链接分为两种:硬链接和软链接,ln默认建立硬链接(hard link),两种的区别请自己搜索:)
    最常用参数:
    -s        —-建立软链接(符号链接,可以理解为win下的快捷方式)
    -f        —-如果要建立的链接名已经存在,则删除之

    ls:
    显示目录内容
    最常用参数:
    -a        —-显示指定目录所有文件,包括文件名以 . 开头的文件
    -l        —-显示文件详细信息(包括文件类型,权限,修改时间,访问时间,大小,文件名…)
    -h        —-将文件大小以方便阅读的形式表示出来,配合 -l 参数使用,常有奇效

    man

    最常用参数:
    man 阿拉伯数字
    阿拉伯数字1: 可执行程序(一般为用户安装的程序,如果提供了manpages的话)和shell命令
    阿拉伯数字2: 系统调用(例如 open调用,socket调用,chmod调用 等),先装manpages-dev先
    阿拉伯数字3: 库函数调用(例如 man 3 printf),先装manpages-dev先
    …….
    当你执行man ls 时, 和 man 1 ls结果是一样的,因为ls在man手册中只有一个入口
    当你想看chmod调用的手册页时,就要特别指定 man 2 chmod了~~因为chmod不止有一个入口
    在man的时候,可以通过j,k上下移动(和vi中类似),可以通过/查询,通过n,N查找下个,上个匹配(和vi类似)
    q退出(也和vi类似….)
    比较有意思的一点:
    由于man 本身是个命令,所以,连man都是可以man的 =.=

    mkdir:
    创建一个目录
    最常用参数:
    -p        —-如果给出的路径中父目录不存在,则同时创建父目录

    mount:
    挂载文件系统(可理解为挂载一个分区)
    最常用参数:
    -t        —-指定文件系统类型,比如iso9660(挂载iso镜像为光盘,相当于虚拟光驱),ntfs,ext3,rfs等等
    -l        —-列出所有已经挂载的文件系统,支持卷标
    -a        —-挂载fstab中记录的所有分区
    -n        —-挂载的时候不写入/etc/mtab
    -o        —-相当常用的一个参数,指定挂载文件系统的”选项”,比如noatime,用来挂载BT专用分区很合适
    mv:
    移动或者更名文件,取决于目的目录是否为当前目录
    最常用参数:
    -b        —-为每个已经存在的目的文件做个备份(防止覆盖)
    -f        —-不提示是否覆盖已经存在的目的文件
    -i        —-与-f参数相反
    -u        —-仅当源文件比目的文件更新或者目的文件不存在时候才移动
    -v        —-显示移动文件的进度(个人总是推荐使用此参数,明白你在做什么)

    ps,top:
    列出当前命令的执行状态,ps为静态,top为动态(top时’q'退出)
    ps:这个命令本人更常用些,推荐给你看看=.=
    最常用参数(ps多用参数集合,而不是单个参数,并且配合grep使用)
    -ef        —-以标准语法列出当前所有进程状态,例如ps -ef | grep eva #列出eva的进程状态
    aux        —-以BSD语法列出………………………………..
    -ejH    —-列出进程树
    -eLf    —-同时列出线程状态

    rm, rmdir:
    rm:删除文件或目录,rmdir:删除一个空目录(此命令个人认为没啥用,可以用rm -r替代)
    rm最常用参数:
    -f        —-不提示不存在的文件,直接跳过
    -i        —-每个删除动作都提示 (=.= 删除多的话岂不是烦死)
    -I        —-删除多个文件(多于3个时)或者递归式删除(对于非空目录)提示一次
    -r和-R    —-递归式删除该目录下的一切东东
    -v        —-显示每个文件的删除动作(个人总是推荐使用此参数,明白你在做什么)

    sudo,su:
    sudo我们主要用来临时提升权限,主要用以管理员(超级用户)的权限来运行命令,当需要修改当前登录用户力所不能及的文件/目录
    时需要用sudo,或者su -c,当然sudo和su的作用范围不仅仅如此
    可以使用visudo来编辑/etc/sudoers文件来修改sudo更详细的动作(比如记住密码的时间戳长度)

    tar:

    打包/解包
    这个tar不多说了吧..到处都是tar.gz,tar.bz2的东东
    和ps命令一样,tar一般不用单个参数,而是多个参数的组合,记住参数x是解压(extract),c是创建包(creat)即可
    最常用参数:
    -xvf    —-详细列出解包的步骤
    -cvf    —-详细列出打包的步骤
    -j        —-用来说明这是个tar.bz2包,例如tar -xjvf myfile.tar.bz2
    -t        —-列出包中的文件列表
    —–打包时常追加的参数:
    -r        —-追加到压缩包中
    -u        —-只把比包中更新的文件追加进去
    -h        —-不把符号链接添加到包中,而是添加此符号链接指向的文件
    附加说明:tar是个太强大的东东,常用的操作也就是打包解包,高级功能还是参阅man =.=

    touch:
    修改文件时间戳,默认包括修改时间和创建时间,默认修改为当前时间,默认如果文件不存在就新建一个文件

    最后,附加一个比较详细,权威的文档

    http://wiki.ubuntu.org.cn/index.php?title=UbuntuSkills&variant=zh-cn