Nodejs周末随想:数据 vs 代码

Nodejs周末随想:数据 vs 代码

1. 程序 = 数据结构 + 算法

这是瑞士计算机科学家Niklaus Wirth写的一本书:Algorithms + Data Structures = Programs。这本书揭示了算法和数据结构之间的紧密关联关系。

Wirth是几种计算机编程语言的设计者,包括Pascal和Modula-2等。他获得了1984年的图灵奖。

从另外一个角度,这个句话也说明了程序就是代码(指令)作用于数据。

2. Arduino之哈佛体系结构

当前计算机的主流体系结构是冯诺依曼结构,其中一个很重要的概念是“存储程序”:代码和数据统一保存在内存中。由于冯诺依曼曾经在普林斯顿大学高等研究院工作,所以也叫做普林斯顿体系架构。

Arduino是一个开源的电子平台,创意工作者和设计人员用它制作好玩的交互硬件产品。为了测试Johnny Five框架,我特意买了一个Arduino UNO R3的板子以及一些周边硬件。在实验中,我发现Arduino采用的是哈佛体系结构:代码和数据分别使用不同的存储。具体来说用32KB Flash存储保存程序,用2K 静态内存保存程序处理的变量等,还有1K EEPROM持久性地保存某些数据。

3. OOP vs FP

Object无疑是面向对象程序设计(Object Oriented Programming,OOP)的核心概念,它把数据和对数据的操作(代码)封装在一起。OOP主要关注Object的组合。

Function是函数式编程(Functional Programming,FP)的核心概念。FP的函数有一个重要性质是:函数的输出仅仅与函数的输入参数相关,不会修改程序的全局状态。从这个意义上,我们可以把纯函数视为一段处理代码,数据流进函数,处理完后流出函数,即实现了数据和代码的分离。这种结构很适合并行计算和分布式处理的实现。FP主要关注Function的组合。

4. 轻量级虚拟机 vs Docker容器

其实容器(container)技术由来已久,如Solaris系统的Zones和FreeBSD的Jails。就是Linux系统,也早就有OpenVZ和LXC。那为什么大家都没有Docker这么声势浩大呢?不知道,也许是创始人或者投资者有很好的营销手段和广泛的人脉吧。

细分起来,OpenVZ/LXC与Docker创建的容器是不一样的。前者创建的是轻量级虚拟机,它们有自己的启动服务和配置,用户通常在一个容器中安装应用所需的应用服务器、数据库等等,相当于应用的数据(状态)和代码都封装在一台容器中。而Docker的容器每次没有启动服务,所以建议用户每个容器就运行一个无状态应用程序,数据(状态)是以数据卷的形式附加到容器上。也就是Docker容器把代码和数据分离了。

5. 结束语

  • 冯诺依曼结构、OOP和轻量级虚拟机:封装了代码和数据;
  • 哈佛体系结构、FP和Docker容器:分离了代码和数据。

看资料若有所思,暂且记下来,还请大家多指正。


2 回复

Nodejs周末随想:数据 vs 代码

1. 程序 = 数据结构 + 算法

这是瑞士计算机科学家Niklaus Wirth在他的著作《Algorithms + Data Structures = Programs》中提出的一个观点。这本书强调了算法和数据结构之间的密切关系。Wirth不仅是Pascal和Modula-2等编程语言的设计者,还因此获得了1984年的图灵奖。

从另一个角度来看,程序本质上是代码(指令)对数据进行操作的结果。例如,在JavaScript中,我们可以定义一个简单的函数来处理数组数据:

// 定义一个处理数组的函数
function sumArray(arr) {
    return arr.reduce((acc, curr) => acc + curr, 0);
}

const numbers = [1, 2, 3, 4, 5];
console.log(sumArray(numbers)); // 输出 15

在这个例子中,sumArray 函数是对数据 numbers 进行操作,体现了代码对数据的处理。

2. Arduino之哈佛体系结构

当前计算机普遍采用的是冯·诺依曼结构,其中代码和数据共存于同一内存空间。然而,Arduino采用的是哈佛体系结构,代码和数据分别存储在不同的存储器中。例如,Arduino UNO R3使用32KB的Flash存储程序,2KB的静态内存用于存储程序运行时的变量,1KB的EEPROM用于持久化存储数据。

// Arduino 示例代码
void setup() {
    Serial.begin(9600);
    pinMode(LED_BUILTIN, OUTPUT); // 初始化内置LED引脚
}

void loop() {
    digitalWrite(LED_BUILTIN, HIGH); // 点亮LED
    delay(1000); // 延迟1秒
    digitalWrite(LED_BUILTIN, LOW); // 关闭LED
    delay(1000); // 延迟1秒
}

在这个例子中,代码和数据是分离的,程序代码存储在Flash中,变量和状态信息存储在静态内存中。

3. OOP vs FP

面向对象编程(OOP)的核心是对象,它将数据和对数据的操作封装在一起。例如,JavaScript中的类可以很好地体现这一点:

class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }

    getArea() {
        return this.width * this.height;
    }
}

const rect = new Rectangle(10, 20);
console.log(rect.getArea()); // 输出 200

函数式编程(FP)则强调函数的纯度,函数的输出仅依赖于输入参数,不修改全局状态。例如:

function add(a, b) {
    return a + b;
}

console.log(add(10, 20)); // 输出 30

在这个例子中,add 函数只处理输入参数 ab,不涉及任何外部状态,体现了数据和代码的分离。

4. 轻量级虚拟机 vs Docker容器

轻量级虚拟机(如OpenVZ和LXC)包含了自己的启动服务和配置,应用的状态和代码一起封装在同一个环境中。而Docker容器则更倾向于将代码和数据分离,每个容器只运行一个无状态的应用程序,数据以数据卷的形式附加到容器上。

# 创建Docker容器
docker run -d --name myapp -v /data:/app/data myimage:latest

在这个例子中,/data 目录被挂载为 /app/data,数据和代码分离,便于管理和扩展。

结束语

  • 冯·诺依曼结构、OOP和轻量级虚拟机:封装了代码和数据;
  • 哈佛体系结构、FP和Docker容器:分离了代码和数据。

希望这些思考对你有所帮助,欢迎讨论和指正!


在 Node.js 的上下文中,“数据 vs 代码”的讨论同样具有重要意义。以下是一些相关的示例和解释:

1. OOP vs FP

OOP 示例

class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

const user = new User('Alice', 25);
user.sayHello();

在这个例子中,User 类将数据 (name, age) 和操作这些数据的方法 (sayHello) 封装在一起。

FP 示例

const sayHello = (name, age) => {
  return `Hello, my name is ${name} and I am ${age} years old.`;
};

console.log(sayHello('Alice', 25));

在这个例子中,函数 sayHello 接收数据作为输入,并返回处理后的结果。函数的输出仅依赖于输入参数,不改变程序的全局状态。

2. 轻量级虚拟机 vs Docker 容器

在 Node.js 应用中,我们可以通过环境变量或配置文件来管理数据和代码的分离。例如:

环境变量

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  const data = process.env.MY_DATA;
  res.send(`Data: ${data}`);
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,MY_DATA 环境变量用于存储应用的状态数据,而不是硬编码在代码中。

总结

Node.js 提供了多种方式来实现数据和代码的分离,通过函数式编程和配置管理,可以更好地管理和维护应用的状态。这样的做法有助于提高代码的可读性和可维护性,同时也便于并行计算和分布式处理的实现。

回到顶部