话说小菜过做已近3年,虽出身PHP后项目大多涉及.net,系统也做得比较繁杂,从常见的CMS,企业OA,ERP,也涉及到电商系统的开发定制,爬虫,工具不一而足,其中web系统居多。

由于表现良好,时常会被经理叫去:“小菜,人是需要成长的啊,不如下个项目你负责吧,锻炼一下吧。”可是小菜对这种负责的职位是相当的不感冒,小菜只想快乐的编码,小菜的最终成为soho一族陪着美女环游世界。都知道事情一涉及到管理,负责就不那么纯洁了。并且小菜一直认为:将帅无能,累死三军。于是小菜每次都以“更对编码感兴趣” 为由拒绝。然而小菜知道丑媳妇早晚要见公婆,时间久了,这一步总是要过的,于是小菜也每每在项目之前,之后尝试以自己的理解,去搭一个架子,以备将来负责时不时之需。

于是“小菜白话搭架子”系列便出现了,会结合一些项目进行分析与记录,促进成长,水平有限,不喜勿喷哦。

闲话少绪,小菜给大家道一下整个的项目背景。

背景:此项目是为欧美某信息服务公司A加工其世界范围内所合作的的“信息提供商”提供的信息。也就是为A设计开发一个数据处理管道使用其不同的合作商,使不同合作商的数据最终为A所用。

由于小菜公司与A公司长久合作关系,大部分的合作商数据处理工具以开发完成,目前小菜们所要做的架子主要是将这些工具组合在一起,使开发过程减少人工干扰,减少人工成本。同时可适用于未来的需求扩展。

开发完成的Tool,及步骤:

  1. DownloadTool:从信息提供商下载数据。
  2. Diff:为数据提供商本身数据去重。
  3. Caculate:整合新版本数据与库中数据,生成新数据。
  4. View:生成用户可用数据。
  5. Backup:数据备份。

因为小菜认为做开发解决方案一定要在技术选型之前,如果先做技术选型的话,可能会我们的思考产生束缚,

小菜第一次获取以上信息时,由于这么多的Tool,将来还可能扩展,本能的想到了一个模型,就是ToolBox。

这样的话,将来那些新开发的Tool或已有的Tool之间就不需要产生本质的结合,将来我们就需要将他们扔进一个叫做“Toolbox"的文件夹中,MainServer会检索这个文件夹,将新增的Tool加载进系统运行程序集,有些类似于插件开发。由于经理对于Wcf有个人的青睐,要求使用wcf做选型的分布式信息架构,说实话小菜不喜欢wcf,因为小菜一直认为这又是微软的一个学院派产品,配置麻烦也不酷。不过用就用吧。

于是小菜认为,既然头脑中有了模型,技术有了选型,开始最喜欢的代码吧:

小菜的结构与分层大概是这样的:

小菜为每一个Tool都做了一个接口,MainServer和Tool之间通过wcf进行通信,mainserver通过检测Tool的心跳获知其生活状态,Tool内有一个线程定时回调方法去Mainserver查找有没有分配自己的Task,Tool获取Task之后执行,返回给客户端:

代码如下:

server.contract:

[ServiceContract]

public interface IView {

[OperationContract]

Int32 CreateWork(UpstreamViewsWF work, Int32? seriesID);

[OperationContract]

Boolean TryTakeWork(out GeneralWork<UpstreamViewsWF> work);

[OperationContract]

void UpdateWork(GeneralWork<UpstreamViewsWF> work);

[OperationContract]

void DeleteWork(Int32 id);

[OperationContract]

void ReportProcess(WorkProgress progress);

[OperationContract]

void ReportCompletion(GeneralWork<UpstreamViewsWF> work);

}

service:

public class View: ApplicationService, IView {
private Logger _logger;
private IGeneralJobRepository _generalRepo;
private IJobStatusHistoryRepository _historyRepo; public ViewsService(
IRepositoryContext context,
IGeneralJobRepository generalJobRepo,
IJobStatusHistoryRepository historyRepo)
: base(context) {
_generalRepo = generalJobRepo;
_historyRepo = historyRepo;
_logger = LogManager.GetCurrentClassLogger();
} public Int32 CreateWork(Views work, Int32? seriesID) {
_logger.Info(String.Empty);
GeneralJob job = new GeneralJob {
Category = (Byte)WorkCategory.Views,
Status = (Byte)WorkStatus.Created,
}; if (seriesID.HasValue && seriesID.Value > 0) {
job.SeriesID = seriesID.Value;
} work.TypeName = WorkCategory.Views.ToString(); job.VARS = JsonConvert.SerializeObject(work);
try {
Context.BeginTrans();
_generalRepo.Create(job);
_historyRepo.Create(CreateJobStatus(job)); Context.Commit();
return job.ID;
}
catch (Exception ex) {
_logger.ErrorException(String.Empty, ex);
throw FaultData.CreateFaultException(ex);
}
} public GeneralWork<Views> RetriveWork(int id) {
_logger.Info(String.Empty);
try {
GeneralJob job = _generalRepo.RetriveByKey(id);
return job.Map<Views>();
} catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void UpdateWork(GeneralWork<Views> work) { _logger.Info(String.Empty); try { GeneralJob job = _generalRepo.RetriveByKey(work.ID); if (job.Status != (Byte)WorkStatus.Created) { Exception ex = new Exception("Only new work could be modified"); } work.VARS.TypeName = WorkCategory.UpstreamViewsWF.ToString(); job.SeriesID = work.SeriesID; job.VARS = JsonConvert.SerializeObject(work.VARS); Context.BeginTrans(); _generalRepo.Update(job); _historyRepo.Create(CreateJobStatus(job)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void DeleteWork(Int32 id) { _logger.Info(String.Empty); try { GeneralJob job = _generalRepo.RetriveByKey(id); if (job.Status != (Byte)WorkStatus.Created) { Exception ex = new Exception("Only new work could be modified"); } job.Status = (Byte)WorkStatus.Abandoned; Context.BeginTrans(); _generalRepo.Delete(job); _historyRepo.Create(CreateJobStatus(job)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public void ReportProcess(WorkProgress progress) { _logger.Info(String.Empty); } public void ReportCompletion(GeneralWork<Views> work) { _logger.Info(String.Empty); try { GeneralJob job1 = work.Map<Views>(); job1.Status = (Byte)WorkStatus.Finished; Context.BeginTrans(); _generalRepo.Update(job1); _historyRepo.Create(CreateJobStatus(job1)); Context.Commit(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } public GeneralWork<Views>[] ReadWorkQueue(int currentPage, int itemsPerPage, WorkStatus? status, string key, outPageClause pageClause) { _logger.Info(String.Empty); try { List<Expression<Func<GeneralJob, Boolean>>> filters = new List<Expression<Func<GeneralJob, bool>>>(); filters.Add(e => e.Category == (Byte)WorkCategory.UpstreamViewsWF); if (status.HasValue) { filters.Add(e => e.Status == (Byte)status); } if (!String.IsNullOrWhiteSpace(key)) { filters.Add(e => e.VARS.Contains(key.Trim())); } PageClause<GeneralJob> jobs = _generalRepo.RetriveAll(currentPage, itemsPerPage, true , p => p.ID, filters.ToArray()); pageClause = new PageClause(jobs); return jobs.Map<UpstreamViewsWF>().ToArray(); } catch (Exception ex) { _logger.ErrorException(String.Empty, ex); throw FaultData.CreateFaultException(ex); } } }

对Tool的封装:

class Program

{

static lWork<View> currentWork;

private readonly static string exePath = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "app.exe" );

static void Main( string[] args ) {

Trace.Listeners.Add( new ConsoleTraceListener() );

try {

if( TryTakeWork() ) {

Trace.WriteLine( "Take a work" );

Work();

ProcessWork();

ReportCompletion();

}

} catch( Exception ex ) {

Console.WriteLine( ex );

}

}

static void Work() {

using( ServiceFactory factory = new ServiceFactory() ) {

try {

ISeriesWorkService service = factory.CreateChanel<ISeriesWorkService>();

SeriesWork seriesWork = service.RetriveWork( currentWork.SeriesID );

currentWork.VARS.TypeName = ConfigurationManager.AppSettings[ "TypeName" ];

Trace.WriteLine( "TypeName:" + currentWork.VARS.TypeName );

currentWork.VARS.Code = seriesWork.egion;

Trace.WriteLine( "Code:" + Code );

CopyHelper.CopyDir( Path.GetFullPath( @"..\..\Application\" ), AppDomain.CurrentDomain.BaseDirectory );

} catch( Exception ex ) {

Console.WriteLine( ex );

}

}

}

static Boolean TakeWork() {

Trace.WriteLine( "TryTakeWork" );

using( ServiceFactory factory = new ServiceFactory() ) {

IUpstreamViewsWFService service = factory.CreateChanel<IUpstreamViewsWFService>();

return service.TakeWork( out currentWork );

}

}

static void ProcessWork() {

Trace.WriteLine( "ProcessWork..." );

Process process = null;

try {

ProcessStartInfo info = new ProcessStartInfo();

info.CreateNoWindow = false;

info.FileName = exePath; //as u need

process = Process.Start( info );

process.EnableRaisingEvents = true;

process.WaitForExit();

Trace.WriteLine( "ProcessWork succeed" );

} catch( Exception EX ) {

Trace.WriteLine( "Exception:" + EX );

if( process != null ) {

process.Kill();

}

}

}

static void ReportCompletion() {

Trace.WriteLine( "ReportCompletion" );

using( ServiceFactory factory = new ServiceFactory() ) {

IView service = factory.CreateChanel<IView>();

service.ReportCompletion( currentWork );

}

}

}

话说一天过去了,小菜把基本的功能完成了,小菜想反正也有时间于是小菜把他知道的东西都用上了IOC(unit),Log4,Orm(ef)。慢慢的小菜开始将接口丰富了越来越多的功能,最后小菜对经理说了自己的想法,说了用的技术,经理说好"下午部署上吧“,小菜心想我的接口已经有了很丰富的功能,我还提供了很多其他功能的接口,肯定没问题于是小菜欣然的答应了。然而新的挑战就这样悄然的反生了。

他找到每个Tool的开发人员讲解自己的接口怎样用,能做什么,需要与MainServer以怎样的方式进行通信,不同异常机制信息的提供的不同。小菜发现他对每一开发者讲解的时候,大家更多的是关心自己的Tool应该更少的关注Mainserver,同时大家也更多的是忙于自己的事情,没有多少时间去协同维护你的接口,大家的一致决定是你先写一个Tool对接Mainserver的Demo我们照着改就可以了,你先写吧。

就这样小菜心想,我已经写的这么好了的接口,为什么大家不喜欢用不喜欢听呢。下班之后小菜一直不思其解,于是拨通了同校大两级也是做开发的学长”老鸟“的电话,简单介绍了事情的经过之后,老鸟呵呵一笑说:“小菜, 你的想法不错,可是就是因为你提供的东西反而太多了,大师不是只懂加法也要会做减法,搭架子要有所为有所不为”。

未完待续。。。

 
 

ToolBox Analysis & Design的更多相关文章

  1. [Design Patterns] 3. Software Pattern Overview

    When you're on the way which is unknown and dangerous, just follow your mind and steer the boat. 软件模 ...

  2. matlab toolboxes 大全

    MATLAB Toolboxes top (Top) Audio - Astronomy - BiomedicalInformatics - Chemometrics  - Chaos - Chemi ...

  3. 软件开发学习笔记 <二>软件开发模型、Up、Rup、敏捷Up

    软件开发过程(process) 是一个将用户需求转化为软件系统所需要的活动的集合. 软件生命周期(SDLC,Software Devlopment Life Cycle) 软件从孕育.诞生.成长.成熟 ...

  4. DDD~概念中的DDD(转)

    概念中的DDD DDD: 领域驱动设计,它是对面向对象的的分析和设计(OOAD,Object Orient Analysis Design)的一个补充,对技术框架进行了分层规划,同时对每个类进行了策略 ...

  5. C++的学习资源

    本文总结了几个好的C++网站,以及C++方面的经典书籍.所列书籍或标准可以到这里找找电子版. wikipedia关于C++有关条目,注意看后面“参考文献”和“外部链接”: C++ programmin ...

  6. 读书笔记系列之java性能优化权威指南 一 第一章

    主题:java性能优化权威指南 pdf 版本:英文版 Java Performance Tuning 忽略:(0~24页)Performance+Acknowledge 1.Strategies, A ...

  7. DDD的思考

    概述 DDD领域驱动设计,它是对面向对象的的分析和设计(OOAD,Object Orient Analysis Design)的一个补充,对技术框架进行了分层规划,同时对每个类进行了策略和类型划分.领 ...

  8. UML Distilled - Development Process

    Iterative(迭代) and Waterfall(瀑布) Processes One of the biggest debates about process is that between w ...

  9. LiangNa Resum

    LiangNa AnShan Street, YangPu, NY @.com OBJECTIVE: Seeking a position to contribute my skills and ed ...

随机推荐

  1. sk_buff整理笔记(两、操作函数)

    承接上一:sk_buff 整理笔记(一.数据结构)这一篇要讲的是内核为sk_buff结构提供的一些操作函数. 第一.首先要讲的是sk_buff中的四大指针: 四大指针各自是:head.data.tai ...

  2. CodeIgniter入门——HelloWorld

    原文:CodeIgniter入门--HelloWorld CodeIgniter(CI)是一套给PHP网站开发者使用的应用程序开发框架和工具包. 初次接触,来一个HelloWorld~~~ ^_^ 准 ...

  3. c++界面设计皮肤工具

    1. 先进行软件界面设计,确定软件界面美术包装方案 2. 依据软件界面美术设计装方案制作对应的图片,图片格式请參见AUDK的帮助文档或皮肤工具SkinTool 的 Demo 3. 打开皮肤工具 Ski ...

  4. java字节中的基本类型的职业的数目 (采访总是问)

    因为移动装置存储器中的移动开发的局限性,数据的字节数需要考虑往往在占领中使用的类型. 下面介绍下一个Java,以加深记忆. 在Java中一共同拥有8种基本数据类型,当中有4种整型,2种浮点类型,1种用 ...

  5. React.js终探(五)

    在React中,一切都是看做组件. 而组件的嵌套也是十分常见的. 所以有的组件就作为容器组件 容器组件 React元素可以包含子元素 如 //JSX <ezpanel title="t ...

  6. [mysql]刷新windows恢复后mysql和&quot;Access denied for user&#39;root&#39;@&#39;IP&#39;&quot;处理问题

    mysql数据库软件实际上是绿色的,重装系统后能够继续使用. 1.重装系统保留原有的后mysql安装文件夹,数据文件夹. 2.制作用于启动一个批处理文件mysql:[run.bat]的文件存储在mys ...

  7. C# 程序自动批量生成 google maps 的KML文件

    原文:C# 程序自动批量生成 google maps 的KML文件 google maps 的 KML 文件可以用于静态的地图标注,在某些应用中,我们手上往往有成百上千个地址,我们需要把这些地址和描述 ...

  8. TypeScript入门

    博客园首发,转载请注明出处,多谢支持.http://www.cnblogs.com/xuema/ 一.TypeScript TypeScript是一种由微软开发的自由和开源的编程语言.它是JavaSc ...

  9. java环境变量配置四种方法

    原文:java环境变量配置四种方法 Java编程首要工作就是安装JDK(Java Development Kit).一通“NEXT”点完安装后就是最重要的环境变量设置了.也许有人会问为什么要设置环境变 ...

  10. MVC验证05-自定义验证规则、验证2个属性值不等

    原文:MVC验证05-自定义验证规则.验证2个属性值不等 本文体验2个属性值不等.即当一个属性输入值,另外一个属性输入的值不能和第一个属性值相等.相关文章包括: MVC验证01-基础.远程验证   M ...