理解 Exit Code 并学会如何在 Bash 脚本中使用

Exit Codes 是什么

在 Unix 和 Linux 系统中,程序可以在执行终止后传递值给其父进程。这个值被称为退出码(exit code)或退出状态(exit status)。在 POSIX 系统中,惯例做法是当程序成功执行时传递 0 ,当程序执行失败时传递 1 或比 1 大的值。

传递状态码为何重要?如果你在命令行脚本上下文中查看状态码,答案显而易见。任何有用的脚本,它将不可避免地要么被其他脚本所使用,要么被 bash 单行脚本包裹所使用。特别是脚本被用来与自动化工具 SaltStack 或者监测工具 Nagios 配合使用。这些工具会执行脚本并检查它的状态,来确定脚本是否执行成功。

其中最重要的原因是,即使你不定义状态码,它仍然存在于你的脚本中。如果你不定义恰当的退出码,执行失败的脚本可能会返回成功的状态,这样会导致问题,问题大小取决于你的脚本做了什么。

如果不指定退出码会发生什么

在 Linux 里,任何在命令行中执行的脚本都有退出码。在 Bash 脚本中,如果脚本里没有指定退出码,退出码将会是脚本最后一个命令执行后产生的状态码。为了更好地解释退出码,下面将给出一个脚本来说明。

脚本

#!/bin/bash
touch /root/test
echo created file

上面的脚本既会执行 touch 命令也会执行 echo 命令。当我们以非 root 用户执行这个脚本时 touch 命令将会执行失败,理想情况下,当我们执行 touch 命令失败时我们希望通过脚本的退出码来表明有命令执行失败。我们可以通过打印 Bash 的特殊变量 $? 来获取退出码。这个变量将会打印出脚本最后一个命令执行的退出码。

执行输出

$ ./tmp.sh 
touch: cannot touch '/root/test': Permission denied
created file
$ echo $?
0

你可以看到,当执行 ./tmp.sh 后退出码是 0 ,而 0 代表脚本执行成功,虽然 touch 命令执行失败了。上面的脚本执行了两个命令:touchecho。因为我们没有指定退出码所以脚本以最后一个命令执行后的状态码退出。在这个例子中,最后运行的是 echo 命令,这个命令确实执行成功了。

脚本

#!/bin/bash
touch /root/test

如果我们去掉脚本中的 echo 命令,我们将看到 touch 命令的退出码。

执行结果

$ ./tmp.sh 
touch: cannot touch '/root/test': Permission denied
$ echo $?
1

你可以看到,因为最后运行的命令是 touch ,所以脚本的退出码正确地反应了脚本的状态:执行失败。

在你的 Bash 脚本中使用退出码

当从我们的脚本中去掉 echo 命令后脚本跑通了并且返回了恰当的退出码。当我们想在 touch 命令执行成功执行一个操作,而在执行失败时执行另一个操作会发生什么。比如脚本执行成功时输出至 stdout ,执行失败时输出至 stderr 这种操作。

测试退出码

前面的代码中,我们使用了特殊变量 $? 来打印脚本的退出码。我们同样可以在脚本中使用它来测试 touch 命令是否执行成功。

脚本

#!/bin/bash
touch /root/test 2> /dev/null
if [ $? -eq 0 ]
then
  echo "Successfully created file"
else
  echo "Could not create file" >&2
fi

在上面的修改版代码中,如果 touch 的退出码是 0 ,脚本将会输出成功的消息。如果退出码是除 0 以外的其他数字,这表示执行失败,脚本将会打印失败的消息到 stderr

$ ./tmp.sh
Could not create file

在程序中提供你自己的退出码

在上面的程序中,虽然 touch 命令执行失败时将会提供一个错误信息提示,但它仍给出了表示执行成功的状态码 0 。

$ ./tmp.sh
Could not create file
$ echo $?
0

既然脚本执行失败了,但它仍然传递执行成功的退出码给其他需要执行此脚本程序显然很不适合。为添加我们自己的退出码到这个程序里,我们可以简单地通过 exit 来实现。

脚本

#!/bin/bash

touch /root/test 2> /dev/null

if [ $? -eq 0 ]
then
  echo "Successfully created file"
  exit 0
else
  echo "Could not create file" >&2
  exit 1
fi

通过脚本里的 exit 命令,我们可以在 touch 命令执行成功时输出成功的消息并返回状态码 0 。当 touch 执行失败时我们将打印失败的消息至 stderr 并返回一个表示失败的状态码 1 。

执行结果

$ ./tmp.sh
Could not create file
$ echo $?
1

在命令行中使用退出码

现在我们的脚本既可以通知用户也能通知程序命令是否执行成功,我们可以使用这个脚本配合其他的管理工具,或者简单地通过 Bash 单行命令使用它。
Bash One Liner:
bash
$ ./tmp.sh && echo "bam" || (sudo ./tmp.sh && echo "bam" || echo "fail")
Could not create file
Successfully created file
bam

上面的命令组使用了在 Bash 里称为 list constructs 的工具。它允许你通过 &&(代表 and)和 || (代表 or)将命令串到一起。上面的命令将会执行 ./tmp.sh 脚本,如果退出码是 0 命令 echo "bam" 将被执行。但如果 ./tmp.sh 的退出码为 1 ,圆括号里的命令将在之后被执行。圆括号里的命令通过 &&|| 被串到一起。

list constructs 使用退出码来知晓一个命令是否执行成功。如果脚本不恰当地使用退出码,其他使用更高阶的命令(比如 list constructs)调用此脚本的用户就可能得到与预期不符的结果。

更多关于退出码的信息

Bash 里的 exit 命令接受不了从 0 - 255 的整形数值,大多数情况下 01 就够用了,不过其他的数值也提供了,为更具体的错误信息做储备。The Linux Documentation Project 有一个不错的 保留状态码 列表,告诉大家这些状态码作何使用。


原文链接:http://
bencane.com/2014/09/02/understanding-exit-codes-and-how-to-use-them-in-bash-scripts/

使用 Chrome 扩展程序 JSON Viewer 进行调试

使用 Chrome 扩展程序 JSON Viewer 进行调试

PHP 调试时有很多种方法,其中最简单的无非是 echo 与 var_dump 、 print_r 以及 debug_backtrace 了。这篇文章要介绍的是平常用的比较多的,适合在调 HTTP 接口以及平常开发中需要输出变量内容的情况。其实在 IDE 中比较适合使用 XDebug 或者断点调试,这样能在运行时直接查看当前上下文的各个变量,不过这种情况不在此篇讨论之列,后续我也将介绍相关的方法,来完善这个系列。

现在步入正题。在平常和前端的配合中经常会有一些 RESTful 接口输出,而其中最常用的内容传输格式就是 JSON ,JSON 在 PHP 中可以很方便地转化为对象或者数组,在打印变量时使用 JSON 再配合浏览器的扩展进行解析,无疑能提高开发效率。

JSON

先用两张图来了解一下 JSON 的格式,这样就不会混淆其在 PHP 中所代表的意思。

对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。

值(value)可以是双引号括起来的字符串(string)、数值 (number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。

Chrome 扩展

JSON viewer 扩展的地址是 https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh

JSON view GitHub 官网介绍了其有如下 feature

  • 语法高亮
  • 23 个内置的主题
  • 节点可折叠
  • 可点击的 url
  • 在控制台「console」输入 json 回车中查看你的 JSON(通过访问 id 为 json 的 HTML 元素)
  • 显示行号选项
  • 在 url 中加入时间戳 header

等等。

PHP 配合 JSON viewer 进行输出调试

PHP 中用来处理 JSON 使用最多的是 json_encode 和 json_decode ,比如你有 array 有如下结构

$arr = array(
            'key1'  => 1,
            1       => 'string',
            'array' => array(
                'value1',
                'value2',
            )
        );

如果使用 var_dump 输出,那么长的是这样

Array
(
    [key1] => 1
    [1] => string
    [array] => Array
        (
            [0] => value1
            [1] => value2
        )

)

当层级不够多,数组元素不够多,肉眼观察根本不是问题,但是一旦数据变得复杂,输出将会非常难看且不易查找,这时候一个美观的输出外带查看层级和数据复制功能会显得很方便,此时,你只需要 echo json_encode($arr);exit; ,扩展会自动解析 JSON 。

最终你得到的可能是这样的 UI:

好了,其实还有很多输出调试工具,比如 symfony 的 var-dumper 既能输出 HTML 的调试信息,又能在 cli 下输出带格式的调试信息。还有 debug helper Kint 、Yii 的 yii-debug-toolbar 以及强大的 XDebug 。


FaceBook 命令行 UI PathPicker

FaceBook 命令行 UI PathPicker

早先在逛 Facebook 后端开源项目时看到了一个命令行工具 PathPicker ,安装后试用了一下感觉还不错,恰好项目开发时在使用 Git ,发现结合 PathPicker 后免去了很多麻烦。

试想以下场景:
1. 你完成一个功能会涉及到不少文件,你得小心翼翼地一个个文件选择,防止不必要的文件出现在同一个待提交列表中;
2. 你改了很多文件,然后执行了 git add . ,这时你有两个选择,要么 git rest 不想在这次提交中包含的文件,要么一个个选择,然后 添加到 git commit 的后面。
于是 PathPicker 出现了,专为解决此种费力不讨好的事情,UI 选择器,命令行,一起上。

介绍

FaceBook PathPicker 是一个简单的命令行工具,用来处理选择 bash 文件输出时的问题。
PathPicker 做以下事情:

  • 通过管道处理输入中所有表现出文本特性的文件
  • 在一个方便选择的 UI 容器里展现管道输入
  • 然后你可以对输入做以下事情:
    • 用你最喜欢的编辑器处理选择的所有文件
    • 利用输入执行任意命令

下面通过一段视频来了解 PathPicker:

PathPicker 是怎么运行的

PathPicker 是 bash 脚本和一些 Python 模块 结合后的产物。 它主要有以下三个步骤:

  1. 首先在 bash 脚本中,它将所有的标准输入重定向到一个 Python 模块,然后通过解析取出其中所包含的文件名候选列表。每个候选文件名都将被用来与文件系统做比对确保其存在,再然后,会把处理结果保存至临时文件并终止 python 脚本的运行。
  2. 第二部,bash 脚本会切换至命令行输入模式,并且另一个 python 模块会读取出已保存的条目并使用 curses 在一个 UI 选择器展现它们。
  3. 最后,python 脚本会输出一条命令至 bash 文件,最终被原始的 bash 脚本解析执行。

使用示例

当改了很多文件需要提交提交时,查看当前状态 git status

PathPicker-git add 前
将输出重定向至 PathPicker git stataus | fpp
PathPicker-git status|fpp 后

  • 已选中为绿色
  • 已选中且当前光标悬停显示为红色
  • 未选中且当前光标悬停显示为蓝色
  • 无法选中的光标无法跳到此项,显示为纯文本

提交选定的文件 git commit $F
PathPicker-git commit $F

PathPicker 官网见 http://facebook.github.io/PathPicker/


Git 常用操作

Git 常用操作


  1. Git 忽略已追踪文件的修改
    git update-index –assume-unchanged /path/to/file
    Git 取消忽略文件的修改 (再次追踪此文件)
    git update-index --no-assume-unchanged /path/to/file
  2. 导入 Git 仓库至 Bitbucket
    1. create repository in Bitbucket
    2. do upstreaming in local
      cd /path/to/my/repo
      git remote add origin https://username@bitbucket.org/username/reponame.git
      git push -u origin --all # pushes up the repo and its refs for the first time
      git push -u origin --tags # pushes up any tags

MySQL 单机多实例主从

environment

[root@iZ25qtxg0q6Z ~]# uname -a
Linux iZ25qtxg0q6Z 2.6.32-431.23.3.el6.x86_64 #1 SMP Thu Jul 31 17:20:51 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@iZ25qtxg0q6Z ~]# cat /etc/redhat-release
CentOS release 6.7 (Final)
[root@iZ25qtxg0q6Z ~]# mysql --version
mysql  Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1

set-up replication steps

  1. enable binary logging of master
  2. stop writing FLUSH TABLES WITH READ LOCK;
  3. obtain binary log file name and position for slave
  4. transfer data from master to slave (mysqldump 、 mysqlimport)
  5. on the master UNLOCK TABLES;
  6. Setting the Replication Slave Configuration

    CHANGE MASTER TO
    MASTER_HOST='master_host_name',
    MASTER_USER='replication_user_name',
    MASTER_PASSWORD='replication_password',
    MASTER_LOG_FILE='recorded_log_file_name',
    MASTER_LOG_POS=recorded_log_position;
    
  7. check master and slave status SHOW VARIABLES LIKE 'server_id'
  8. in slave START SLAVE

安装过程中的命令及问题解决方法

mysql_secure_installation

mysql_secure_installation 作用:

  • set root password,
  • disallowing root login remotely,
  • removing anonymous user accounts after first installation and
  • removing test database which can be accessed by any users

但是 mysql_secure_installation 无法指定命令参数(5.7 可以指定参数以后可以直接指定,之前的版本无法指定),会使用默认的配置,导致新安装的实例安全配置无法更新 配置位置 /var/lib/mysql/mysql2.sock

有两种方法可以解决执行 mysql_secure_installation 时应用到指定实例:

[root@iZ25qtxg0q6Z ~]# which mysql_secure_installation
/usr/bin/mysql_secure_installation
  1. 在配置文件中制定,修改为对应的实例配置
  2. 使用 软链

启动 mysql instanse

mysqld_safe --defaults-file=/etc/my2.cnf

主从数据保持一致(导出导入)

  1. 导出数据 mysqldump --all-databases --master-data --events > dbdump.db -p
  2. 导入至指定实例 mysqlimport -uroot -P 3380 -h 127.0.0.1 dbdump.db -p

stop mysql instance by specifing sockct

mysqladmin -S /var/lib/mysql/mysql2.sock shutdown -p

userful links

  1. mysql 安全设置
  2. 使用软链
  3. kill process
  4. config slave error handlering
  5. restore mysqldump file
  6. reset mysql root password
  7. create-multiple-mysql-instance
  8. multiple-mysql-servers
  9. Setting Up Replication with New Master and Slaves

MySQL 索引类型


有必要对数据库的索引类型及其实现做个了解及总结。

Question:

  1. 书中所说索引分为单列索引,主键索引以及联合索引;
  2. 在数据库的 GUI 软件中却可以对一个表设置三种类型的索引:分别为 normal、unique、full text;
  3. 在 MySQL manual 中创建 index 的语法为 CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type]

    ON tbl_name (index_col_name,...)

    index_col_name:

    col_name [(length)] [ASC | DESC]

Answer:

疑惑解决: 第一种分法是按照列的数量进行分类,第二、三种是按照索引类型进行分类

  • normal index 为普通索引
  • primary index 为主键索引,索引列的值必须唯一且不为空
  • unique index 为唯一索引,索引列必须唯一但可以为空
  • fulltext index 为全文索引,只能对 CHAR,VARCHAR 和 TEXT 列编制索引,并且只能在 MyISAM 表中编制
  • spatial index 为空间索引,只能对空间列编制索引,并且只能在 MyISAM 表中编制

有时间再对其具体实现及背后使用的算法做了解及总结。 可能的关键字如下: 1. HASH 2. B-TREE 3. B+TREE

为网站全站链接添加参数

为网站全站链接添加参数

需求

为网站链接添加参数,可以统计用户在网站中的流向,以及确定网站经常访问的部分。

解决方案

  1. 在程序生成链接的时候附带转向,这样需要改变所有生成链接的地方
  2. 使用 jQuery 在网站加载时动态改变网站页面内所有链接

利弊

使用第一种方案时当需要改变某一页面的来源时,所有与本页面有关的链接都需要改动,好处是页面输出到浏览器后即为用户最终所得,不存在链接参数错误的问题。 使用第二种方案好处是修改页面链接时只需在页面标签的父级标签添加某一属性(如例子给出的 from),即可定位相当精准,但弊端在于此方法必须在页面 DOM 树加载完成之后执行,假如中途 DOM 树出问题或者标签属性输出不全可能导致链接错误,另外当 标签内的链接由 JavaScript 单独进行定义时需额外修改,这是两种方案都要面对的问题。

使用 jQuery 实现的版本

思路:

1、查找所有 a 节点 2、获取其父类,一级一级往上找,使用 closest() 查找,获取其 from 参数值 3、判断 a 节点的 href 属性是否包含?,包含则直接添加 &from ,否则添加?&from。如果添加 href 为 javascript: 或者 javascript:void(0) 时则不改变其 href 属性 前提:链接不是 javascript: 且链接父级标签含有属性 from 如网页链接为 www.jayxhj.com 标签层级为 <p from="top"> <a href="/test"></a> </p>
则执行 addparam() 之后变为
<p from="top"> <a href="/test?f=top"></a> </p>

样例:www.baidu.com 转换后为 www.baidu.com?f=top www.baidu.com?r=test 转换后为 www.baidu.com?r=test&f=top

function addparam(){
 $( "a").each( function () {
     var realhref = $.trim($( this).attr( 'href'));
     var href = '';
     if (realhref.indexOf( '?') === -1) {
         href = realhref;
     } else {
         if (realhref.indexOf( '&#038;') === -1) {
             if (realhref.indexOf( 'f=') === -1) {
                 href = realhref;
             } else {
                 var hrefarr = realhref.split( '&#038;');
                 var length = hrefarr.length - 1;
                 for ( var i = 0; i < length; i++) {
                     href += hrefarr[i] + '&#038;';
                 }
                 href = href.substring(0, href.length - 1);
             }
         } else {
             var hrefarr = realhref.split( '&#038;');
             if (realhref.indexOf( 'f=') === -1) {
                 href = realhref;
             } else {
                 var length = hrefarr.length - 1;
                 for ( var i = 0; i < length; i++) {
                     href += hrefarr[i] + '&#038;';
                 }
                 href = href.substring(0, href.length - 1);
             }
         }
     }
     if (!~href.indexOf( 'javascript:') &#038;& href !== '') {
         var parent = $( this).parents();
         for ( var j = 0; j <= parent.length; j++) {
             if ( typeof ($(parent[j]).attr( 'from')) != 'undefined') {
                 $( this).attr( 'href', href + (href.indexOf('?' ) === -1 ? '?' : '&#038;' ) + 'f=' + $(parent[j]).attr('from' ));
                 break;
             }
         }
     }
 });
 }

具体可参看 股票雷达网站

我的 web 开发学习之路

我的web开发学习之路

最初了解到web是从自己使用网站,又因为专业的缘故,所以对编程对web开发逐步有了概念。学校论坛算是启蒙,因为管理着后台,其实并不怎么需要编码,无非是挖掘Discuz的功能,整合现有资源,并应用到论坛,服务论坛上的用户,比如找朋友、签到打卡、搬运工(学校通知、考试安排等)这些功能。

学校的课程体系中包含HTML、CSS、JavaScript、JSP动态网页、XML、JAVA这些课程,正是这些课程让我逐步对web开发感兴趣,让我花时间去了解在这之外的东西,才慢慢地走上了web开发之路。但不得不说道路是曲折的,有过弯路有过徘徊,还好度过了那个时期,没有中途离开,否则也就没有这篇文章了。

一无所知

静态网页-->动态网站

最开始对web的理解就是网页,互相连接起来的网页,才有可能形成world,大家都在使用才能wide,所以加上网页就形成了WWW。后来又发现网站都是动态的啊,纯静态网站那是十多年前的事情了呢,于是知道原来有动态网站和动态语言。最先看到的当属asp了,在w3school上,形形色色的网页都是asp后缀的呢。于是开始在w3chool上学习HTML与CSS,刚开始的过程无疑是新奇有趣又略有困难的,很多概念不懂,需要不断回顾再学习。这时候JavaScript是让我觉得神奇的语言,因为不需要服务器,只需要浏览器的引擎即可操纵网页,轻易修改。

动态网页最先接触的是JSP,因为恰好学习Java,使用JSP无疑是比较好的选择,使用一本叫作《Servlet/JSP深入详解》的书籍作为入门以及应付考试。了解了9大内置对象,了解了如何使用JSP与后台JAVA进行交互,但始终没有用它做点什么东西出来。后来还是跟着解丹老师做某一个项目,使用FLEX作为前端代替了JSP,这是后话。

逐步形成概念

网站组成

由于身处计算机专业,又待在网络中心,与学校论坛的前辈们在一个地方做事情,所以难免学着去了解Discuz这个系统。因为种种原因,加入了论坛团队,担任技术组组长一职。论坛可谓我网站启蒙。因为网站的运行运营以及各种困难问题的解决离不开团队成员的配合与努力,这段期间可谓各自努力学习,都希望把前人所作的工作做好同时让论坛在学校火热起来,其实还有一个目的,就是让我们院系能在学校被熟悉起来,因为曾说自己是信工的,被问居然还有这个院系!!

由于论坛工作的原因,那时对网站粗浅的理解就是网站是社区。由于要和其他院系以及学校组织做活动,因此得准备活动的素材来应对这些活动。所以对网站的组成做了初步的了解。最先做的大概就是Banner了,使用阿里妈妈的工具做,只需找好素材,然后根据活动主题做相应改变。

网站大概由前后端以及相应的组件组成,这些组件包括Banner、flash广告,图片轮播等等。

网站思考

这段时期我对网站做了相应的思考,其实论坛说到底是一种以话题做主线的社区,大家因为相同的志趣而集合到一起,因为相同的话题而产生交流。失去了话题论坛活跃度必然降低,所以可以看到,学校论坛中学校通知、租房、杏林广播、聚餐吃饭、爆照这些话题是经久不衰,其他话题如灌水吐槽等不能长久,但是可以作为润滑剂,毕竟干货以及热门话题需要时间,不会一直都有,既需要引导也需要刻意制造。

技能学习

静态部分学习

由于动态网站课程的学习,于是顺带地学习了HTML、CSS、jQuery。但也只是很粗浅的入门。一方面原因是眼界不够,觉得无非就这些知识,类似于XX天精通XXX,但实际上有很大的误导,因为任何一门技术研究起来实际上都不是三言两语就可以解释清楚的。比如你学习了HTML,觉得它无非标签的嵌套以及网页的布局,有什么难的呢。可是写过之后会知道根本不是这样。问题:行内元素和块级元素有什么区别,它们能相互嵌套吗?如果只是学习了标签是不会知道这个问题的答案的。即使了解了这个问题的答案,又会发现它们嵌套后在不同浏览器下效果是不同的,因为浏览器的解析引擎不一样,效果就有所区别了。

实习时由于要做一个内部的系统,其中有个需求是根据日期选择数据,这种需求如果是自己来实现必然费时,而如果使用jQuery的组件就是几段代码的工作量。jQuery给我最大的益处就是其丰富的DOM对象API,基于这些API,对DOM元素的操作变得无比简单,而且由于其对多浏览器的支持,可以简单地开发出适配手机端的网页。

技能的学习让我深深觉得,每一门技术都有好坏,重要的根据需求选择技术并根据应用场景合理地配置,以便达到开发的目的。

服务器配置

每一种服务背后都有前人巨大的工作量作为铺垫,比如Apache、Memcache、Redis、Nginx等。

最初搭建论坛使用的是WAMP套件,因为不熟悉Linux而且Windows服务器也够用,所以长久以来也没有更换。

搭建起网站并运行起来最基本的就是设置网站文件目录,并支持动态语言文件的解析,即转发给指定的解析引擎进行解析并返回。套件的好处就是这些设置有可视化的界面,而且有基本够用的设置,不怎么需要额外修改,坏处是可定制性差一点,但是每个阶段有每个阶段的重点。

实际上做WEB开发最好还是在Linux平台下。因为常用的服务大都是在Linux下进行更新,Windows系统下这些服务一般也会有人维护,但总是会慢一拍,而且有些服务根本不能在Windows下运行。

域名、空间以及DNS

最初由于想使用自己的名字作为网站名搭建博客程序,就去了解了空间及域名。后来由于使用jayxhj网名,就购买了jayxhj.com这个域名。空间最初准备使用万网的空间以及域名,后来发现实在太贵,一年保守估计1K以上,索性购买美国的空间,使用的是老薛主机, 优点是不需要备案,而且客服支持不错。

工具

最初接触网站并上传文件使用的是FlashFXP, 后来才了解到使用SVN或者Git利用hook机制上传代码既方便快捷又能回溯,而且由于天然的版本机制,对代码控制和new feature的并入是非常好的选择。

WEB开发体系逐步形成

由于大四实习的需要,在找到实习后得以有机会了解到真实的网站开发以及团队协作的流程。

技术选择

对于个人而言,选择一门主要的语言,使用合适的工具,了解足够多的技术并应用,业余学习新技术新语言,无疑是大多数开发者的常态。而对于公司而言,最初会选择一定的技术满足线上的需求,当选择的技术无法支撑需求时会考虑进行优化或者重构以及更换技术方案。由于论坛的接触,以及PHP天然地适合web开发,于是我选择了PHP作为自己的主要开发语言。

开发流程

最初加入的是股票雷达,公司是创业型互联网金融公司,十人左右的团队,每个人负责一大块,PHP这边有三个人,iOS开发一人,技术总监一人,Java开发一人,产品经理一人,CEO一人,再加上实习几人,平常的业务会外包给别人做。

公司使用Asana作为团队协作工具,任务的分发以及任务的标记完成,使得需求转化成具体可操作的技术任务。一般是由产品经理与CEO推出需求,然后与开发人员协商,给出工作安排,CEO负责资源的配置,即将任务合理分发,产品经理跟进项目的执行并及时反馈,再根据反馈及时调整,以合理控制项目进度。当前端切好页面并调好效果时一般总监会把架构设计好了,后端也把基本的代码设计及接口做好了,这时候就是前后端的整合,整合完成后移交给产品经理做基本测试,然后就是beta版发布,发布之后就是根据运营数据做调整,同时跟进开发新的功能,以及修复过去开发的产品的缺陷及bug。

开发框架的选择

有句话叫作:不要重复造轮子。由于有太多的框架给我们选择,所以从头开发实无必要。框架好在把路由、逻辑分发、代码包含、分层架构做的非常好,而且内置变量还能让开发过程更简洁高效,代码可读性也更好,最重要的是OOP的框架能让开发者注重逻辑的实现而无需纠结于细节。

团队配合

无论是即时交流还是延时交流,这些都涉及到工具的选用,比如团队协作工具,比如企业邮箱选择,比如bug管理,比如IM,比如版本控制。实习给我最大的感触就是不论什么事情,要尽心尽力,及时沟通,搞的定的及时做好后期继续优化,搞不定的请教别人,而不是拖到deadline。因为项目的完成一般是需要协作的,涉及到常见的业务逻辑问题,肯定需要多人的参与,这时及时的沟通就显得尤为重要。工作不比学校,别人为你的工作付出了薪水,所以理应尽最大努力保质完成,即使不能完成也要能找到最好的平衡点,让项目流畅运转。

WEB开发提高

就好比PHP不仅仅是一门脚本或者模板语言,要想学好技术,绝不能仅仅局限在某一门技术上,因为技术的应用范围有限,没有哪个技术能通吃所有方面,在合适的场景下选用合适的技术考虑实现难易综合成本才是比较明智的选择。而技术上的积累,在深度和广度上的平衡,最终会带来质变。

Linux基础

推荐学习鸟哥的Linux私房菜. 基础学习篇,无论是计算机基础知识的回顾,还是Linux的基本概念,这本书都讲的浅显易懂又不致枯燥无味。

面向对象开发

面向对象最大的特点就是封装继承与多态。使用面向对象开发能较容易地实现代码的封装与隔离,使用封装实现数据与数据处理的结合,使用继承可以方便扩展已有封装模块,而多态则实现多变的需求,统一的接口,不同的实现。

MVC

建议看看这个回答

三层构架和 MVC 不同

数据库

无论是关系型数据库还是非关系型数据库(Not Only SQL),数据库都是应用的核心,而且往往应用的瓶颈集中在数据库,这也是 NoSQL 兴起的一大原因,互联网巨大的用户量与数据量使得传统的关系型数据库不堪重负,而 NoSQL 能分担部分压力且表现良好。

代码结构与分层设计

代码结构的设计可以使得资源放在合适的目录,且结构清晰的代码能降低后期维护的成本。提前画好层次结构图,理清代码的设计思路,将应用分层设计,把接口定义良好,可以为后续的开发减轻不少压力。

新技术的学习

新技术的学习无疑是不被社会淘汰最有可能的途经。因为淘汰的常常是不肯学习的人,多学习多思考,跟上先进技术,才能有更好的为应用带来本质的改进。

比如 Node.js 与 PHP 的配合可以使得 API 设计变得更为合理,使用 MongoDB 作为日志分析收集器等等。这些技术的应用往往来自现实中的需求,而只要你的公司你的产品在成长,这些问题迟早会遇到。

涨薪是原动力,做更好的应用是实际需求,更好的服务用户是愿景。

架构

只有从初级工程师一级一级往上爬,当技术积累到一定程度,能带领一个团队做事时,这时候是技术人证明自己的时候,通过好的产品来诠释自己,让同行让团队尊重,也是对自身最好的嘉奖。

总结

一路走来,最大的感觉是成就感与辛苦是同在的。通过实习找到了互联网公司,敲开了互联网之路。而这一路上难免会有犹豫和徘徊,学校非主流语言,不太好的成绩,这些在后来并不被重视的东西当初却是让我对自己产生怀疑的源泉。但好在互联网这一行,不讲出身不相信命运,相信的是个人的努力,相信的是努力之后的结果。现在仍有太多的东西需要学习,仍有不少东西值得去尝试,好在,热血常在,心未凉,一切都值得去探索。

找工作及基本技能储备

面试准备 1. 技能准备:数据库、数据结构、算法、HTTP、程序语言 2. 目标公司寻找及相关技能准备 3. 应聘方式:内推、校园招聘、社会招聘 4. 自我项目展示:博客、论坛、开源项目参与等 网站搭建 1. 域名购买、DNS 配置 2. 开发环境 (IDE、编辑器 VIM emacs、调试环境 WAMP、设备) 3. 需求分析及了解 4. 原型设计 5. 前端界面设计 6. 后台程序开发 7. 代码调试 8. 网站上线 团队构成 1. 技术研发部:开发部、前端 2. 无线部门 3. 运行维护部门 4. 测试部门 5. 产品设计部:设计部、产品部 6. 人力资源部 PHP 笔试题、知识结构、进阶书籍 PHP 基础 PHP 手册(时常翻阅)、《PHP 和 MySQL web 开发》、《PHP 经典实例》、《PHP 与 MYSQL 权威指南》、《PHP 必须知道的 300 个问题》、《PHP 实战 1200 例》、《PHP 模块开发大全》、《PHP MVC 开发实战》一般来说所有的 PHP 应用程序可以在 CMS/Shop/BBS 这三种网站的模块中找到逻辑。 PHP 提高 《高性能 PHP》《PHP 应用程序安全编程》《PHP 开发与最佳实践》《PHP MVC 开发实战》《精粹 PHP》。 软件架构
soap mvc socket 了解就行了 框架了解就行了 MongoDB、Redis、memcache 知道基本的使用就行 分布式 主从和优化 数据库方面
基础:MySQL 手册 、《MySQL 经典》、《SQL 基础教程》 提高:《高性能 MySQL》、《高可用 MySQL》、《MySQL 的架构设计和性能调优》 中间件方面 了解 CDN 、Vanish、 Squid 、 thrift 、PHPrpc HTTP 《图解 HTTP》、《HTTP 权威指南》 Linux 《鸟哥的 Linux 私房菜: 基础学习篇》、《Linux 系统命令及 Shell 脚本实践指南》 架构方面 《构建高性能 web 站点》《负载均衡优化策略》 算法数据结构 严蔚敏的《数据结构》 链表、栈、二叉树、 排序的那些东西一般排序(快速 二分查找)

email 中 To、Cc、Bcc 字段的作用

你应该确保你的邮件正确地发给了你想要的人。To、Cc、Bcc 域允许你指定合适的策略让收件人接收信息。 To 字段是为那些与邮件信息极度相关且随时需要作出回应的人准备的。如果你认为谁与此极度相关,你应该把他们包含在 To 域中。 在邮件的开头把所有你认为相关的人都写进来是个不错的方法,这样你可以让别人知道谁参与了此事。 比如这样的开头:Hi Bill, Ted, Mary, Suzy, 如果你的收件人超过了四个,那么你最好以 Hi all or Hello team 开头,而不是以上面的方式。 只要你喜欢,你可以添加尽可能多的邮件地址到 To 字段中。有人错误地认为 Cc 域是用来解决收件人过多时的解决方法。 Cc 域(抄送)用来发送给那些你认为应该知道这件事情但又不是特别相关的人:他们仅仅需要知道事情的进展而不需要为此做出回应。 对于那些在 80 年代之后出生的人来说,“抄送”来源于用打字机写信。你需要把两张纸同时放入打字机中,中间放一张复写纸。信的内容通过复写纸被复印到底下的那张纸中。这样在底下就留下了与第一个信件相同的副本。 你有很多种使用 Cc 域的理由

* 他保证被包含进来的人在这个环内(常被用来让经理们与及时跟进此议题)
* 他让人们明白他们是应该对此作出回应还是仅仅只需知道就好了
* 他允许你让收件人知晓其他的人也知道正在发生什么(万一你想让别人重视这件事情,或者把他作为重要的事情对待)。

Bcc 域(密送)被用来当你希望其他人收到这个邮件,但是你不想除收件人以外的人知道他收到了这封邮件。 当人们收到邮件,他们能看到 To,Cc 域但是看不到 Bcc 域的收件人。 当你发送邮件给成千上万的人时,使用 Bcc 无疑是不错的选择。你不想让收件人知道其他收件人的邮件地址,所以你使用它,而不是 To,或 Cc。 总结下来就是这样: To 发送给那些需要响应的人 Cc 发送给那些需要知晓事情进展但是不需要做出行动的人 Bcc 发送给那些不需要知道其他收件人的人或者用于大量的邮件发送

原文地址:http://www.writebetteremails.com/to-cc.htm

看国内各大邮箱服务提供商,基本提供了以上三种发送方式,To 对应在收件人中填写多个邮箱地址,Cc 对应于添加抄送,Bcc 对应于添加密送,当然还有分别发送(QQ 邮箱)或群发单显(网易和新浪),这种服务将多个发送任务放入队列中分别发送,收件人会依次收到相同的邮件。