代码即数据思想带来的思考


前言:

首先大家都听说过“代码即数据”这句话,但是这里要说的“代码即数据”可能会有不同的意思,个人的意思是,我们在开发过程中有好多的时候是数据信息驱动或者状态驱动的。

说的白话些,就是我们之前的好多开发都有明确的业务需求,同时开发过程中会使用我们熟练的解决方案。但是有的时候上手一个自己之前完全不熟悉的项目或者在项目中使用了我们不擅长的一些组件或技术的时候,一切的开发似乎变得不可控了。这个时候的驱动往往就变成了针对于我们真正关心的数据的处理。比如,我们针对于一些需求想好了解决方案,但是在执行与实施过程中可能会出现一些不可控的因素使得我们不得不改变到新的解决方案上去,这样的话有可能之前已经code的代码必须重来,同时从原有的业务逻辑中剥离代码也将是一个痛苦的过程。但是不变的就是我们所要去处理的数据,这就是我所说的”数据信息驱动“。

那么”代码及数据“的核心是什么?

核心就是把控整个项目的数据生命中数据状态的变化。针对于每一个状态变化节点,这些变化的东西扔给代码之外的组件进行管理控制。

2个例子:

比如之前听说过一个哥们自己开发推荐系统,由于他对于推荐系统的搭建完全不熟悉,并且不确定哪些数据可用,所以他决定先把架子搭起来,但是后期的算法Code他准备通过文本文件的形式加入系统中,于是此后的程序执行方式就变成了,程序加载到一些指定地方时候会读取文本文件,再将文件信息当作程序的一部分进行执行。(听着有没有一种TDD的赶脚),由于之前的代码是由他们的CTO使用perl写的,后来项目完全交由这个哥们负责,考虑到自己不熟悉prel并且在某些嵌套算法中Perl的效率很低,于是他又将一些核心的算法从主程序中剥离出来(perl的那一部分),考虑后期使用自己熟悉的python实现,所以最终的系统就是这个由中程序框架负责业务+数据流转,细节实现+变化拓展交由文本数据代码实现,取得了不错的成绩。

第二一个例子是一个哥们也是做一个数据流转系统,但是在数据流转过程当中会经由不同的操作系统及终端,并且在开发过程中接入了很多现有的解决方案帮助细节处理,所以他的设计方式是在每一次临界点的时候进行结扎,细节处理交由程序外控制,这就是所说的“分部式”,每一步你可以放在DB中,也可交由文本文件或其他组件。

一个小例子:

考虑到python,php的弱类型,以及C#的强类型,我们将数据的处理需要依赖反射实现。

比如业务为:

由于这种方式最重要的就是识别出变化的位置与节点并将其脱离开来。

例子结构如下:

我们将适配的方式完全交由反射处理,建立TaskHandlerMap.xml


<?xml version="1.0" encoding="utf-8" ?>
<TaskHandlerClassMap>
<TaskHandlerItem>
<FunctionName>CreateDisk</FunctionName>
<TaskHandlerName><![CDATA[DiskOperation]]></TaskHandlerName>
<MessageModelName><![CDATA[DiskMessage]]></MessageModelName>
</TaskHandlerItem>
<TaskHandlerItem>
<FunctionName>CreateVm</FunctionName>
<TaskHandlerName><![CDATA[VitureMachineOperation]]></TaskHandlerName>
<MessageModelName><![CDATA[VirtualMachineMessage]]></MessageModelName>
</TaskHandlerItem>
</TaskHandlerClassMap>

我们在TaskManager模仿一个消息的传递与接受:


    public class TaskManager
{
public void DoWork() {

string json = @"{JobMethod:‘CreateDisk‘,DiskId:1,VirtualMachineId:1,DiskName:‘testDisk01‘}";

TaskHandlerItem taskHandlerItem = ReflectInterface.GetMessgeTaskHandlerInstance(json);
ITaskHandler taskHandler = ReflectInterface.GetTaskHandler("RabbitMQ.Reflect", "RabbitMQ.Reflect.TaskHandlerClass." + taskHandlerItem.TaskHandlerName.ToString());
BaseMessage baseMessage = ReflectInterface.GetBaseMessage("RabbitMQ.Reflect", "RabbitMQ.Reflect.TaskMessage." + taskHandlerItem.MessageModelName.ToString(), json);
if (taskHandler != null) {
taskHandler.TaskProgress += taskHanadler_TaskProgress;
}

Thread workThread = new Thread(taskHandler.DoWork);
workThread.IsBackground = true;
workThread.Start(baseMessage);
}

void taskHanadler_TaskProgress(TaskHandlerEventArgs e)
{
String returnMessageJson = e.ToString();

//update message table
System.Console.WriteLine(e);
}
}

对应的核心反射处理类:reflectInerface:


{
public class ReflectInterface
{
static String _xmlpath = @"D:\zcj-project\RabbitMQ.Console.Client\RabbitMQ.Reflect\TaskXmlMap\TaskHandlerMap.xml";
//get messageTaskHandler instance by message
public static TaskHandlerItem GetMessgeTaskHandlerInstance(string message)
{
try
{
JObject jObject = JObject.Parse(message);
String methodName = jObject["JobMethod"].ToString();
return SerializerXml(methodName);
}
catch (Exception ex) {
throw ex;
}
}

//get xml serializer info
private static TaskHandlerItem SerializerXml(String jobMethod)
{
TaskHandlerItem taskHandlerItem = null;
using (Stream stream = new FileStream(_xmlpath, FileMode.Open, FileAccess.Read))
{
XmlSerializer serializer = new XmlSerializer(typeof(TaskHandlerClassMap));
TaskHandlerClassMap _taskHandlerClassMap = serializer.Deserialize(stream) as TaskHandlerClassMap;
if (_taskHandlerClassMap != null) {
foreach (TaskHandlerItem _taskHandlerItem in _taskHandlerClassMap.TaskHandlerItems)
{
if (_taskHandlerItem.FunctionName == jobMethod) {
taskHandlerItem = new TaskHandlerItem();
taskHandlerItem.MessageModelName = _taskHandlerItem.MessageModelName;
taskHandlerItem.TaskHandlerName = _taskHandlerItem.TaskHandlerName;
break;
}
}
}
}
return taskHandlerItem;
}

//get ITaskHandler instance
public static ITaskHandler GetTaskHandler(string assemblyName, string classNameSpace)
{
try
{
object instance = Assembly.Load(assemblyName).CreateInstance(classNameSpace);
if (instance != null)
{
return (ITaskHandler)instance;
}
else
{
throw new Exception("did not find instance");
}
}
catch (Exception ex) {
throw ex;
}
}

//get BaseMessage instance
public static BaseMessage GetBaseMessage(string assemblyName, string classNameSpace,string message)
{
try
{
object instance = Assembly.Load(assemblyName).CreateInstance(classNameSpace);
if (instance != null)
{
object messageModel = JsonConvert.DeserializeObject(message,instance.GetType());
return messageModel as BaseMessage;
}
else
{
throw new Exception("did not find instance");
}
}
catch (Exception ex)
{
throw ex;
}
}
}

public class TaskHandlerClassMap {
[XmlElement("TaskHandlerItem", IsNullable = false)]
public List<TaskHandlerItem> TaskHandlerItems { get; set; }
}

public class TaskHandlerItem
{
[XmlElement("FunctionName", IsNullable = false)]
public String FunctionName { get; set; }

[XmlElement("TaskHandlerName", IsNullable = false)]
public String TaskHandlerName { get; set; }

[XmlElement("MessageModelName", IsNullable = false)]
public String MessageModelName { get; set; }

}
}

建立TaskHandler类的方法:


    public interface ITaskHandler:IDisposable
{
event Action<TaskHandlerEventArgs> TaskProgress;
void DoWork(object baseMessage);
}

public class TaskHandlerEventArgs : EventArgs
{
private object _messageModel;
public TaskHandlerEventArgs(object messageModel) {
this._messageModel = messageModel;
}
public String Message {
get { return _messageModel.ToString(); }
}
}

AbstractTaskHandler:


    public abstract class AbstractTaskHandler:ITaskHandler
{
public abstract void DoWork(object baseMessage);
public void Dispose()
{
Thread.CurrentThread.Abort();
}

public abstract event Action<TaskHandlerEventArgs> TaskProgress;
}

具体的业务实现类:Disk:


    public class DiskOperation : AbstractTaskHandler
{
public override void DoWork(object baseMessage)
{
DiskMessage message = baseMessage as DiskMessage;
string result = "class name is : DiskOperation";
TaskProgress(new TaskHandlerEventArgs(result));
base.Dispose();
}

public override event Action<TaskHandlerEventArgs> TaskProgress;
}

以及VM:


    public class VitureMachineOperation : AbstractTaskHandler
{
public override void DoWork(object baseMessage)
{
string result = "class name is : VitureMachineOperation";

TaskProgress(new TaskHandlerEventArgs(result));
base.Dispose();
}

public override event Action<TaskHandlerEventArgs> TaskProgress;
}

建立对应的Message信息:


    public class BaseMessage
{
public String JobMethod { get; set; }
public String Uuid { get; set; }
}


    public class DiskMessage:BaseMessage
{
public String DiskId { get; set; }
public String VirtualMachineId { get; set; }
public String DiskName { get; set; }
}


    public class VirtualMachineMessage:BaseMessage
{
public String VirtualMachineId { get; set; }
public String VirtualMachineName { get; set; }
public String UserName { get; set; }
}

这样在我们将程序处理的调度交给xml配置,包括后期的sql也可以放进去,减少了后期由于解决方案更改带来的维护不便利的问题。

代码即数据思想带来的思考

时间: 2024-10-23 18:26:31

代码即数据思想带来的思考的相关文章

Kafka session.timeout.ms heartbeat.interval.ms参数的区别以及对数据存储的一些思考

Kafka session.timeout.ms heartbeat.interval.ms参数的区别以及对数据存储的一些思考 在计算机世界中经常需要与数据打交道,这也是我们戏称CURD工程师的原因之一.写了两年代码,接触了不少存储系统,Redis.MySQL.Kafka.Elasticsearch-慢慢地发现背后的一些公共的设计思想总是那么似曾相识,再深究一下,就会发现一些隐藏在这些系统背后的数学理论. 生活中产生的大量数据需要交由计算机来处理,根据处理方式的不同分为OLTP和OLAP两大类应

前人的代码(数学思想很重要)

/*N^N = 10^(N*log(N))中,由于 N <1000000000,N*log(N)取值在[0,9000000000],没有超出double数据的范围,没有益处.设N*log(N)的整数部分为intpart,分数部分为fractpart,则N^N = 10^(intpart + fractpart) = 10^intpart * 10^fractpart.其中10^intpart肯定为10的倍数,不影响结果,可忽略.所以:10^fractpart的最高位即为结果(因为0<=frac

云计算给传统行业信息化变革带来的思考

<第六届中国云计算大会>在北京国家会议中心圆满闭幕. 热火朝天.红红火火.如火如荼,这是本届云计算大会带给我的关于中国云计算产业发展的特殊感受. 三年前,关于云计算,更多的还是概念的理解 两年前,关于云计算,更多的还是价值的思考 一年前,关于云计算,还只是小规模的研发.测试.使用 而今天,关于云计算,已经是铺天盖地,动辄几千上万台服务器的规模,推出的产品也全面覆盖了IaaS.PaaS.SaaS,涉及的多种技术甚至超越国外巨头 中国的云计算,已经走在世界前沿. 相比起互联网企业在云计算领域的姹紫

数据同步的一些思考与改进

数据同步的一些思考与改进 背景 闲的没事,自己写了个小网站,搭建在自己国外的VPS上,VPS内存极小(512M),而且还要跑点别的(你懂的),内存更紧张巴巴. 改造之前小网站用到了时髦的Redis,Rabbmitmq,Mysql,那时候阿里云的学生主机内存富足,装这么多中间件压力不大,可到了这样的小内存VPS上,一切都变得水土不服,索性啥中间件都不要了,数据库也不要了. 没了数据库,网站的数据从哪里来?存在哪里? 文本形式持久化到本地磁盘? 国外的VPS不比国内,可能哪天说不能访问就不能访问了,

《代码里的世界观》一、代码和数据

程序世界的两个基本元素 1.程序世界两个基本元素是代码和数据: 2.数据和代码相互伪装: 有的看起来是代码的,实际上是数据 .例如:bool flag = true; true属于代码,这里是数据 有的看起来像数据,却是代码 有的代码在特定时候,可以充当数据. 函数指针是一种特殊的数据,这种数据不会返回给用户.它的作用只是为了更加灵活地处理数据. 代码和数据的关系 1.数据是目的,代码是手段,代码永远是为数据服务的. 2.有什么样的数据,决定了会有什么样的代码. 有的系统对数据要求万无一失,有的

我终于理解了LISP『代码即数据|数据即代码』的含义

以前我一直不能理解LISP里引用的作用,感觉引用和字符串没什么区别.比如:> (define (func) 'ok) > (func) 'ok 这里把引用ok当做了函数func的返回值. 但是我在实现函数式汉语编程的时候,我把代码构造成了一个多叉的语法树,这时候对某一段代码的引用,就是不对代码Eval,直接返回语法树的根节点.类似于: > '(car (a b)) '(car (a b))可是LISP中的引用实际上是一个construct,它可以被car.cdr.即:> (car

.NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,逆袭DDD)

阅读目录: 1.背景介绍 2.过程式代码的真正困境 3.工作单元模式的简单示例 4.总结 1.背景介绍 一直都在谈论面向对象开发,但是开发企业应用系统时,使用面向对象开发最大的问题就是在于,多个对象之间的互操作需要涉及数据库操作.两个业务逻辑对象彼此之间需要互相调用,如果之间的互相操作是在一个业务事务范围内的,很容易完成,但是如果本次业务逻辑操作涉及到多个业务对象一起协作完成时问题就来了. 在以往,我们使用过程式的代码(事务脚本模式),将所有与本次业务事务范围内相关的所有逻辑都写在一个大的代码中

Android NDK开发篇(五):Java与原生代码通信(数据操作)

尽管说使用NDK能够提高Android程序的运行效率,可是调用起来还是略微有点麻烦.NDK能够直接使用Java的原生数据类型,而引用类型,由于Java的引用类型的实如今NDK被屏蔽了,所以在NDK使用Java的引用类型则要做对应的处理. 一.对引用数据类型的操作 尽管Java的引用类型的实如今NDK被屏蔽了,JNI还是提供了一组API,通过JNIEnv接口指针提供原生方法改动和使用Java的引用类型. 1.字符串操作 JNI把Java的字符串当作引用来处理,在NDK中使用Java的字符串,须要相

直接代码POST数据调用WebService

原文:直接代码POST数据调用WebService ps:使用过webservice的童鞋大概都明白它是基于Soap协议交换数据的,同时Soap协议是对HTTP协议的扩展,其实我们就可以认为调用一个WEB服务就是通过http协议GET或POST数据的过程,只不过中间的输入/输出数据是遵守Soap协议格式的标准XML.明白这个道理之后我们就可以通过构造请求数据来模拟调用WEB服务的过程了,具体代码如下: using System; using System.Collections.Generic;