前后端的核心,编程的本质,前端全栈的技术选型,

1,504 阅读13分钟

前端:页面 = 数据 + 模版

在前端开发中,页面是用户直接交互的界面。这些页面通常由数据和模板组合生成。这里的“模板”是指 HTML 结构、CSS 样式和 JavaScript 脚本的组合,它定义了页面的布局和样式,以及用户交互的方式。而“数据”则是指填充在模板中的内容,比如文本、图片、视频等。
当我们访问一个动态网站时,前端代码会请求后端服务器获取数据,然后将这些数据填充到模板中,从而生成最终用户看到的页面。这个过程通常涉及到一些前端框架或库(如 React、Vue.js 等),它们提供了数据绑定和模板渲染的机制。

后端:数据 = 多种来源 + 加工数据

后端开发主要处理数据的收集、存储、加工和提供。在这里,“多种来源”指的是数据可以来自多个地方,例如:

  • 用户输入:通过表单、API调用等方式直接从用户那里获取数据。
  • 数据库:存储大量数据的系统,可以是关系型数据库(如 MySQL、PostgreSQL)或非关系型数据库(如 MongoDB)。
  • 外部服务:例如第三方API(如天气服务、地图服务等)。
  • 内部系统:例如公司内部的其他服务或数据仓库。

“加工数据”则是指后端在提供数据之前进行的处理,比如:

  • 查询数据库:执行 SQL 查询或其他数据库操作来检索数据。
  • 数据清洗和转换:确保数据的质量,将数据转换成所需格式。
  • 业务逻辑处理:根据业务需求对数据进行计算、排序、过滤等操作。
  • 认证和授权:确保请求数据的用户有权限接收数据。

总结来说,前端关注的是如何展示数据和与用户的交互,而后端关注的是如何处理和提供数据。前端使用模板和数据生成用户界面,后端则负责从各种来源收集和处理数据,最终提供给前端使用。这个过程确保了前后端分离,各自专注于自己的职责,同时通过 API 等方式相互协作。

编程的本质

大家肯定都听说过:程序 = 数据结构 + 算法这句话,后面又有大佬说:算法 = 逻辑 + 控制。
所以编程的本质其实是:程序 = 逻辑 + 控制 + 数据结构(Programs = Logic + Control + Data Structures)

逻辑 (Logic)

逻辑是程序的基础,它涉及到决策制定和问题解决的过程。逻辑确定了程序如何处理数据,如何进行计算,以及如何根据输入作出相应的输出。例如,逻辑可以包括简单的数学运算,如加法和乘法,也可以包括更复杂的决策和推理过程。

控制 (Control)

控制是程序流的指导机制,它决定了程序的执行顺序。控制结构使得程序能够根据条件选择不同的执行路径(如 if-else 语句),重复执行某段代码(如循环结构 for、while),或者将程序划分为可重复使用的模块或函数。控制流程是编程中的基本概念,它允许程序动态地根据不同的情况作出反应。

数据结构 (Data Structures)

数据结构是组织和存储数据的方式,以便可以高效地访问和修改。不同的数据结构适用于不同的问题和任务。在合适的数据结构之上会承载着很多的业务数据,所以选择合适的数据结构对于程序的性能和效率至关重要。
例如:

  • 数组允许存储一系列相同类型的元素,可以通过索引快速访问。
  • 链表提供了一种动态的数据存储方式,允许在序列中任意位置高效地插入和删除元素。
  • 栈和队列分别支持后进先出和先进先出的数据访问模式。
  • 树和图结构允许表示和处理层次数据和网络关系。

结合理解

在实际的程序设计中,逻辑、控制和数据结构是相互依赖和紧密结合的。没有逻辑,程序就没有方向和目的;没有控制,程序就无法管理复杂性;没有数据结构,程序就无法有效地处理和组织数据。
举个例子:
将这三个组成部分结合起来,我们可以创建出能够解决特定问题的程序。例如,一个简单的计算器程序会使用基本的数据结构来存储用户输入的数字,使用逻辑来处理这些数字(如执行加法、减法等操作),并使用控制流来决定何时执行哪个操作以及如何显示结果。

写好代码的四个步骤

  1. 梳理 data,业务数据
  2. 梳理 logic,使用流程图、DSL、设计模式
  3. 编写 control,控制代码
  4. 不断的重构和优化

我们以一个表单校验器为例讲解这四个步骤:

1. 梳理 Data(业务数据)

首先,你需要明确表单需要校验哪些字段,每个字段有哪些校验规则。例如,一个简单的用户注册表单可能包含以下字段和校验规则:

  • 用户名:必填,长度限制,字符限制
  • 密码:必填,长度限制,强度要求
  • 邮箱:必填,格式要求
  • 手机号:选填,格式要求

在这个步骤中,你可以创建一个数据结构来描述这些字段和规则。例如:

const formRules = {
  username: {
    required: true,
    minLength: 3,
    maxLength: 20,
    pattern: /^[a-zA-Z0-9_]+$/
  },
  password: {
    required: true,
    minLength: 8,
    pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/
  },
  email: {
    required: true,
    pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  },
  phone: {
    required: false,
    pattern: /^\+?(\d.*){3,}$/
  }
};

2. 梳理 Logic(使用流程图、DSL、设计模式)

在这一步,你需要设计校验逻辑。可以使用流程图来可视化校验流程,或者使用领域特定语言(DSL)来描述校验规则。设计模式如策略模式可以用来封装各种校验逻辑,使其可以互换。
例如,你可以定义一个策略对象来处理不同类型的校验:

const validators = {
  required(value) {
    return value.trim().length > 0;
  },
  minLength(length) {
    return (value) => value.length >= length;
  },
  maxLength(length) {
    return (value) => value.length <= length;
  },
  pattern(regex) {
    return (value) => regex.test(value);
  }
};

3. 编写 Control(控制代码)

接下来,你需要编写控制代码,这部分代码将负责接收用户的输入,根据定义的规则进行校验,并返回校验结果。例如:

// 定义一个函数用于验证单个字段是否符合一组规则
function validateField(field, value, rules) {
  // 初始化一个数组来存储验证过程中产生的错误信息
  const errors = [];

  // 遍历所有的规则
  Object.keys(rules).forEach(ruleKey => {
    // 获取当前规则的验证值
    const ruleValue = rules[ruleKey];
    // 从一个预定义的验证器对象中获取与规则对应的验证函数
    const validator = validators[ruleKey];
    
    // 如果找到了对应的验证函数
    if (validator) {
      // 根据规则值的类型选择验证方式:如果规则值是函数,则直接使用该函数验证;否则使用验证器中的函数
      const valid = typeof ruleValue === 'function' ? ruleValue(value) : validator(ruleValue)(value);
      // 如果验证失败,将错误信息添加到错误数组中
      if (!valid) {
        errors.push(`Field ${field} failed validation ${ruleKey}`);
      }
    }
  });

  // 返回包含所有错误信息的数组
  return errors;
}

// 定义一个函数用于验证整个表单数据
function validateForm(formData, formRules) {
  // 初始化一个对象来存储所有字段的错误信息
  const errors = {};

  // 遍历表单数据的每个字段
  Object.keys(formData).forEach(field => {
    // 验证当前字段,并获取验证结果
    const fieldErrors = validateField(field, formData[field], formRules[field]);
    // 如果存在错误信息,将其添加到错误对象中
    if (fieldErrors.length > 0) {
      errors[field] = fieldErrors;
    }
  });

  // 返回包含所有字段错误信息的对象
  return errors;
}

4. 不断的重构和优化

最后一个步骤是迭代。你需要不断地重构和优化你的代码。这意味着你需要根据真实的使用场景来测试校验器的性能,处理边缘情况,并改进用户体验。此外,你也可能需要根据业务需求的变化来更新和扩展校验规则。
在这个过程中,保持代码的清晰和模块化非常重要,这样可以使得维护和扩展变得更加容易。你也可以考虑编写单元测试来确保每个校验规则都能正常工作,并防止未来的更改破坏现有功能。

使用

上面校验器在 React 中,这样使用:

import React, { useState } from 'react';

function MyFormComponent() {
  const [formData, setFormData] = useState({
    username: '',
    password: '',
    email: '',
    phone: ''
  });
  const [errors, setErrors] = useState({});

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validateForm(formData, formRules);
    setErrors(validationErrors);
    if (Object.keys(validationErrors).length === 0) {
      console.log('Form is valid, proceed with submission.');
      // 这里可以添加表单提交的代码
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* 表单字段和错误信息显示 */}
      <input
        name="username"
        value={formData.username}
        onChange={handleInputChange}
      />
      {errors.username && <p>{errors.username.join(', ')}</p>}
      {/* 其他字段... */}
      <button type="submit">Submit</button>
    </form>
  );
}

在这个 React 组件中,handleInputChange 函数负责更新表单数据,handleSubmit 函数负责在表单提交时执行校验,并根据校验结果更新错误状态。如果没有错误,你可以继续进行表单提交的后续处理。

前端全栈有哪些技术选型

项目技术选型是项目开发过程中至关重要的一步。合适的技术选型可以提高开发效率,降低维护成本,而不当的技术选型则可能导致项目延期、超预算甚至失败。以下是一些进行技术选型时应考虑的原则:

  1. 项目需求
  • 根据项目的具体需求来选择技术栈。例如,如果项目需要高并发处理,应该选择能够支持这一特性的技术。
  1. 团队熟悉度
  • 考虑团队成员对技术栈的熟悉程度。选择团队成员熟悉的技术可以减少学习成本和开发时间。
  1. 社区支持和生态系统
  • 选择有强大社区支持的技术,这样能够保证在遇到问题时可以快速找到解决方案。同时,一个健全的生态系统意味着有丰富的库和工具可以使用。
  1. 性能
  • 根据应用的性能要求选择相应的技术。例如,对于计算密集型的应用,应选择性能更优的编程语言和框架。
  1. 可扩展性
  • 考虑技术栈的可扩展性,确保随着项目的发展,技术栈能够支持更多的用户、数据和复杂性。
  1. 安全性
  • 安全性是不容忽视的因素,选择时要考虑技术的安全性能和历史漏洞记录。
  1. 成本
  • 考虑技术选型对项目成本的影响,包括开发成本、维护成本和运行成本。
  1. 未来趋势
  • 关注技术的发展趋势和前景,避免选择即将过时的技术。
  1. 兼容性和集成性
  • 考虑技术与项目中已有系统的兼容性,以及与其他技术的集成能力。
  1. 许可和法律问题
  • 确保所选技术的许可证符合项目需求,避免法律风险。
  1. 测试和部署
  • 选择容易进行自动化测试和部署的技术,以提高持续集成和持续部署的效率。

在进行技术选型时,通常需要对上述原则进行权衡,找到最适合项目需求、团队能力和预算条件的技术组合。这通常需要团队成员之间的深入讨论和市场调研,以做出明智的决策。

前端框架

Vue

Vue.js 是一种渐进式 JavaScript 框架,用于构建用户界面。它易于上手,同时在构建复杂应用程序方面也非常强大。Vue 的核心库专注于视图层,并且它非常容易将 Vue 集成到现有的项目中。Vue 也完全能够为复杂的单页应用程序(SPA)提供动力。

React

React 是一个由 Facebook 创建的开源 JavaScript 库,用于构建用户界面或UI组件。它是前端 MVC 框架的视图层,通常用于构建单页应用程序。React的一大特点是虚拟DOM,这种机制可以提高应用的性能,因为只有在必要时才会对实际的 DOM 进行操作。

Solid

Solid 是一个声明式的、用于构建用户界面的 JavaScript 库。它的设计目标是提供类似 React 的开发体验,但在性能上更优越。Solid 使用了一种不同的响应式系统,可以在运行时提供更高效的更新和更少的内存使用。

Svelte

Svelte 是一个新兴的前端框架,与 React 和 Vue 不同,Svelte 在构建时将应用程序编译成高效的 JavaScript 代码,而不是在运行时使用虚拟 DOM。这种方法减少了运行时的开销,使 Svelte 应用程序在性能上通常比使用传统虚拟 DOM 的框架更快。

UI 组件库

Ant Design (Antd)

Ant Design 是一个基于 React 的 UI 库,提供了一套丰富的UI组件,用于构建企业级的 Web 应用程序。它遵循 Ant Design 系统的设计规范,提供了一致和专业的视觉布局。

Element(plus)

Element 是一个为开发者、设计师和产品经理准备的 Vue.js UI 工具套件。它包含一套完备的组件和一系列的设计资源,帮助用户在 Vue 环境中快速构建网站。

Material-UI

Material-UI 是一套 React 组件,用于实现 Google 的 Material Design 指南。通过这个库,可以轻松地将 Material Design 的风格应用到 React 应用程序中。

后端 Node 框架

Express

Express 是一个灵活的 Node.js Web 应用程序框架,提供了一系列强大的特性,帮助你创建各种 Web 和移动设备应用。它被设计成简单、快速、无约束。

Koa

Koa 是由 Express 的原始创建者之一开发的一个新的 Web 框架,旨在成为一个更小、更富表现力、更健壮的基础。Koa 使用 async 函数,这是一种使错误处理更加安全和简单的方法。

Egg

Egg.js 是一个为企业级应用和大型团队打造的 Node.js 框架,它在 Koa 的基础上扩展了一些约定,以此来支持团队开发和插件的生态系统。

Nest

Nest 是一个用于构建高效、可靠和可扩展的服务器端应用程序的框架。它使用现代 JavaScript,是基于 TypeScript 构建的,并且完全支持 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数响应式编程)的原则。

其他

API 规范

API 规范是指定如何设计和使用 API 的一套规则。常见的 API 规范有 REST, GraphQL, gRPC 等。

数据库

数据库是组织、存储和检索数据的系统。它们可以是关系型的,如 MySQL、PostgreSQL,或非关系型的,如 MongoDB、Cassandra。

工程化工具

工程化工具,如 Webpack、Vite、Babel、ESLint 等,用于自动化前端开发过程中的常见任务,提高开发效率和代码质量。

部署

部署是将应用程序从开发环境迁移到生产环境的过程。这可能涉及到服务器管理、容器化技术如 Docker、持续集成/持续部署(CI/CD)流程等。

测试

在软件开发中,测试是确保代码质量和功能正确性的重要环节。常见的测试类型包括单元测试、集成测试和端到端测试。常用测试框架有 Jest、Mocha、Cypress 等。

所以最后我觉得 React + AntD + TS + NestJS + GraphQL + TypeOrm + Mysql 是一套不错的全栈选择。