忆2011年的秋天:一个人的项目

简介:   最近在知乎上看到有人问“一个人开发一个项目是一种怎样的体验?”,这让我想起了2011年刚出道那会儿的项目经历。当时在一家旅游公司工作,整个公司就我一个技术,老板和我们算是校友,通过关系在我们学校招一个人过来做开发,主要维护公司的网站。当时比较流行的社交平台是开心网,老板突发奇想,让我们也做个类似的系统,就叫驴友驿站(目前已经下线),刚出来混,一听要做个这么好玩的系统,马上就一头扎进去了。当时是个热血青年,看到公司的网站是用古老的ASP做的,马上就想将其改版,但碍于时间不够,只能先搁置,完成当前的任务才是该做的事情,顺便为自己将要用的相关技术试试水。

一、准备阶段


1)搜集需求

  虽然大三的时候曾经和学校的前辈一起搞过一个ERP系统,但最终并没有上线,项目做到一半被迫终止了,因此还是非常缺乏项目经验的。现在还是一个人,该如何切入,是我目前面对的首要问题。我首先是搜集需求,没有产品经理就只能自己来,还好对开心网比较熟悉。在粗略的思考过之后,草率的决定先完成以下5个模块:

1、会员模块,包括个人信息、头像、签名、动态、相册等。

2、转帖模块,包括发帖、评论、回复、转发、观点等。

3、日记模块,包括列表、新增、删除、修改等。

4、好友模块,包括搜索、添加、分组、读取好友列表等。

5、私信模块,包含收件箱、发件箱和发送。

  后续又加了圈子和提问模块。整个开发周期大概是一个月时间,每天都是热血沸腾的干着,把这社交系统当成了自己的事业来看待,因此当时的效率非常高。虽然兴致很高,但毕竟缺乏经验,很多时候都是在探索,效率、性能、扩展性、容错性、移植性等架构概念这些都是不存在的(如下图所示),考虑的点只有一个,即效果是否和目标一样。当时还是IE6大行其道的年代,写页面很多时候都要与IE6斗智斗勇,经常会出现其它浏览器都正常,就偏偏IE6有问题,每次都要为它开小灶,处处受限,又不得不适配,那种滋味很复杂。


36.jpg


2)编辑器和数据库

  在确定好需求后就是设计数据库,先建立了十多张表,包括会员、帖子、好友关系、私信、评论、日记等,凭着感觉设计的,后期在开发过程中进行了不断地调整。在学校用的是Visual Studio 2008,正好老网站的数据库用的是MSSQL 2000,都是微软的东西,很好结合,省了兼容的操作。


37.png


39.png


二、开发过程


  工具都准备好后,就直接开搞了,当时也不懂前后端分离,因此没有做静态页面,直接是边写后台边写页面,导致现在下线后,我都无法看到页面,必须把环境搭建好后,才能浏览页面。

1)后台

  抛开性能和扩展性,当时社交系统主要碰到的问题主要集中在前端效果,后台碰到的棘手问题不多,此处只列举记得的几个小问题:

1、公司原先有个老式的BBS系统,里面也聚集了几万的用户,这次的社交系统中的会员要和这个BBS内的会员打通。

2、好友动态包括转帖、评论、上传照片、圈人等都算是动态,这些都会展示在个人主页中,用户量一大,该如何保存以及怎么才能不遗漏的添加这些信息。

3、好友关系的维持,在数据库中该怎么保存这层关系。

2)前端

  在完成这个系统后,得到了很大的成就感(虽然同事和用户的吐槽非常多),不过这些成就感并不来自于后台看不见的数据逻辑处理,而且前端各个能看到能操作的脚本特效,这也为我日后转岗前端埋下了伏笔。

  当时是个前端菜鸟,但还很固执的拒绝使用jQuery这个强大的第三方DOM库,想法很简单,就是觉得初学者应该用原生的,这样能更好的理解这门语言。虽然出发点没有错,但是后期结构组织不合理,使得代码冗余且混乱不堪。刚开始写前端也不懂分模块,就把大部分的逻辑脚本都写在了一个文件内(包含了2700多行代码),只有一个函数,各个功能作为该函数的原型方法存在,如下代码所示,调代码还得找半天才能定位。


function sysInfo(redirect,page){
    this.redirect=redirect;//ajax路径
    this.page=page;//页数
    this.row=15;
}
sysInfo.prototype.createXMLHttpRequest=function(){
    if (window.XMLHttpRequest) {  
         xmlHttp = new XMLHttpRequest();   
         if (xmlHttp.overrideMimeType)
             xmlHttp.overrideMimeType("text/xml");  
     } else {  
         if (window.ActiveXObject) {  
             var activexName = ["MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];  
             for (var i = 0; i < activexName.length; i++) {  
                 try {   
                     xmlHttp = new ActiveXObject(activexName[i]);  
                     break;  
                 }  
                 catch (e) {  
                 }  
             }  
         }  
      }
   return xmlHttp;
}
sysInfo.prototype.updatePhotoTitle=function(){
    var oThis=this;
    var title=document.getElementById("TxtTitle").value;
    var id=document.getElementById("HdTitleId").value;
    var xmlHttp=oThis.createXMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState == 4) { 
         if (xmlHttp.status == 200) {
            if(xmlHttp.responseText=="success"){
                document.getElementById("SpTitle").innerHTML=title;
                document.getElementById("modifyTitle").style.display="none";
            }
            else 
                alert(xmlHttp.responseText);
         }
      }
    }
    var param=new Array();
    param[0]="type=updateTitle";
    param[1]="id="+id;
    param[2]="title="+escape(title);
    param[3]="random="+Math.random();
    var url = oThis.redirect+"?"+param.join("&");
    xmlHttp.open("GET", url, true);  
    xmlHttp.send(null);
}


  还犯了一个错误,当时刚接触Ajax,异步加载直接震撼到我了,产生了一个奇怪的观点,即只有异步才是好的体验。然后全局都用异步来加载,不管合不合适一刀切,但像私信收件箱、好友列表等这些内容用后台直接渲染会更简单。虽然前端有模板引擎,但自己根据不知道有这玩意儿,因此HTML代码就全部都用字符串拼接实现,如下代码所示,整个文件充斥着这些拼接语句。


sysInfo.prototype.getSmsRecive=function(){ 
    var oThis=this;
    var loading=document.getElementById("loading");
    loading.style.display="block";
    var xmlHttp=oThis.createXMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState == 4) { 
         if (xmlHttp.status == 200) {   
             loading.style.display="none";
             var div,divBox;
             divBox=document.getElementById("smsInfo");
             while(divBox.hasChildNodes())
                divBox.removeChild(divBox.lastChild);
             var divArray;
             if(xmlHttp.responseText==""){
                div=document.createElement("div");
                div.className="dxx_of";
                divArray=new Array();
                divArray[0]="<div style='padding: 15px 10px;' class='dxx1'></div><div class='dxx4'>暂无邮件</div><div class='cb'></div>";
                div.innerHTML =divArray.join("");
                divBox.appendChild(div);
                return;
             }
             if(xmlHttp.responseText=="redirect")
                window.location.href="../../login/userLogin.aspx";
             var splits=xmlHttp.responseText.split("|");
             var divInfos = eval("("+splits[0]+")");
             for(i=0;i<divInfos.length;i++){
                div=document.createElement("div");
                div.className="dxx_of";
                divArray=new Array();
                divArray[0]="<div style='padding: 15px 10px;' class='dxx1'></div>";
                divArray[1]="<div class='dxx4'><div class='l50_s'><a class='sl' href='../home/userHome.aspx?uid="+divInfos[i].Fid+"'>";
                divArray[2]="<img src='../../upload/userface/"+divInfos[i].Up+"' height='50px' width='50px'/></a></div>";
                divArray[3]="<div style='text-align: center; margin-top: -8px;'><a class='sl' href='../home/userHome.aspx?uid="+divInfos[i].Fid+"'>"+divInfos[i].Un+"</a></div></div>";
                divArray[4]="<div style='width: 120px;' class='dxx5'><div class='c9 f12'>"+divInfos[i].Ct+"</div></div>";
                divArray[5]="<div class='dxx6'>"+divInfos[i].Sc+"</div>";
                divArray[6]="<div style='width: 78px;' class='dxx4'>";
                divArray[7]="<div class='bb1d8'><a href=\"javascript:delSms('"+oThis.redirect+"',"+oThis.page+","+divInfos[i].Sid+",'1')\" onclick=\"return confirm('您确定要删除这条短消息吗?')\"  class='sl2_r'>删除该消息</a></div>";
                divArray[8]="<div class='bb1d8'><a href='write.aspx?type=1&un="+escape(divInfos[i].Un)+"'  class='sl2_r'>回复该消息</a></div>";
                divArray[9]="<div class='bb1d8'><a href='write.aspx?type=2&sid="+divInfos[i].Sid+"'  class='sl2_r'>转发该消息</a></div>";
                divArray[10]="</div><div class='cb'></div>";
                div.innerHTML =divArray.join("");
                divBox.appendChild(div);
             }
             divBox.innerHTML+=splits[1];
             oThis.runJs('../../js/sns/sysRequest.js','js','sysRequest.js');
         }
       }
    }
    var param=new Array();
    param[0]="type=recive";
    param[1]="currentPage="+oThis.page;
    param[2]="random="+Math.random();
    var url = oThis.redirect+"?"+param.join("&");
    xmlHttp.open("GET", url, true);  
    xmlHttp.send(null);
}


3)插件

  当然,要想完成页面中的所有效果,肯定需要引入第三方插件。通过搜索引擎,在网上找类似的成品插件或半成品代码段,找到后再修修补补,直到符合预期效果为止。这样来来回回不知道多少次,给我一个感觉,就是前端太难学了,每次都是不带重样的,根本无从下手。

  印象最深的是头像裁剪插件,改了好久,刚开始是无从下手,后面到处翻资料才找到些眉目。最终的做法是先将新照片上传到服务器中(如左图所示),然后载入到本地,接着进行裁剪(如右图所示),期间会计算各种尺寸和坐标,一旦算错,就无法正确裁剪。


38.png

40.png


  后面的插件比头像裁剪都要简单点,基本都只要由前端完成,不需要后台参与,例如转帖最后的好友印象(左图)、照片圈人(右图)等。


41.png


image.png


  这是一次非常难忘的经历,可以说直接影响了我后面的职业发展。虽然现在工作没有以前那么热血了,越来越高冷,但是对技术的热情并没有减弱。对于我来说,唯一遗憾的是当时没有做任何记录,现在已经无法体会到当时的所感和所想,而且这段珍贵的回忆将越来越模糊,如果可以重来,一定会将当时的点滴都详细记下。

相关文章
|
7月前
|
Python
湖南大学第十六届程序设计竞赛(重现赛)补题题解(更新中)
湖南大学第十六届程序设计竞赛(重现赛)补题题解(更新中)
40 0
|
存储 机器学习/深度学习 算法
【蓝桥杯集训·每日一题】AcWing 4074. 铁路与公路
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 Floyd 算法 Spfa 算法
116 0
|
存储 机器学习/深度学习 人工智能
【蓝桥杯集训·周赛】AcWing 第94场周赛
文章目录 第一题 AcWing 4870. 装物品 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4871. 最早时刻 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4872. 最短路之和 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
79 0
|
存储 机器学习/深度学习 人工智能
【蓝桥杯集训·周赛】AcWing 第 95 场周赛
文章目录 第一题 AcWing 4873. 简单计算 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4874. 约数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4875. 整数游戏 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
116 0
|
JavaScript BI
【蓝桥杯集训·周赛】AcWing 第96场周赛
文章目录 第一题 AcWing 4876. 完美数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4877. 最大价值 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4878. 维护数组 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
92 0
|
存储 人工智能 算法
【蓝桥杯集训·最后一次周赛】AcWing 第 97 场周赛
文章目录 第一题 AcWing 4944. 热身计算 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4945. 比大小 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4946. 叶子节点 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
134 0
|
存储 人工智能 算法
【蓝桥杯集训·每日一题】AcWing 3305. 作物杂交
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 Spfa算法
130 0
|
存储 人工智能 BI
【蓝桥杯集训·周赛】AcWing 第91场周赛
文章目录 第一题 AcWing 4861. 构造数列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4862. 浇花 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4861. 构造数列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
87 0
|
存储 人工智能
【蓝桥杯集训·周赛】AcWing 第93场周赛
文章目录 第一题 AcWing 4867. 整除数 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4868. 数字替换 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4869. 异或值 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
106 0
|
存储
【蓝桥杯集训·周赛】AcWing 第92场周赛
文章目录 第一题 AcWing 4864. 多边形 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第二题 AcWing 4865. 有效类型 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 第三题 AcWing 4866. 最大数量 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
127 0