From e051d1b49148ff4e7eb98c795852785299ff8dc8 Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 20 Jun 2024 09:39:23 +0800 Subject: [PATCH] init --- .gitignore | 3 + 1.bmp | Bin 0 -> 31814 bytes book.toml | 6 + src/SUMMARY.md | 11 ++ src/chapter1/deploy.md | 3 + src/chapter1/dev.md | 88 +++++++++ src/chapter1/env.md | 19 ++ src/chapter1/script.md | 1 + src/chapter2/components.bmp | Bin 0 -> 11891 bytes src/chapter2/components.md | 43 +++++ src/chapter2/components.png | Bin 0 -> 11891 bytes src/chapter2/def.md | 51 ++++++ src/chapter2/entities.md | 344 ++++++++++++++++++++++++++++++++++++ src/env.md | 1 + src/intro-1.png | Bin 0 -> 16030 bytes src/intro.md | 36 ++++ 16 files changed, 606 insertions(+) create mode 100644 .gitignore create mode 100644 1.bmp create mode 100644 book.toml create mode 100644 src/SUMMARY.md create mode 100644 src/chapter1/deploy.md create mode 100644 src/chapter1/dev.md create mode 100644 src/chapter1/env.md create mode 100644 src/chapter1/script.md create mode 100644 src/chapter2/components.bmp create mode 100644 src/chapter2/components.md create mode 100644 src/chapter2/components.png create mode 100644 src/chapter2/def.md create mode 100644 src/chapter2/entities.md create mode 100644 src/env.md create mode 100644 src/intro-1.png create mode 100644 src/intro.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0dbe8d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +book + +**.pptx \ No newline at end of file diff --git a/1.bmp b/1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..23f2a370349918d5f156d5231c36a10c3d9d2fe5 GIT binary patch literal 31814 zcmeFZc|4Ts8$YhoDXpYUvP@A_wj^6*TB##x6Dp<%Nl5lEPaPE*OzLE5FqNc`iOJ3k zF(%tgl6@IwV(hb6X2v`-^Luon^ZEVx{pRi z)z(!~Qc`PAo;Y?+N@^(}CH2SnisjIi^ZR7lpkGV;&RHIj%B3icK!5z{e%Si3lvEyi zHF#|q^!Li!Cmj5wq&DxI|F`7ixgBgNsnG6|#|~czcA5|gcuG9SexZ9ZP#GxxD>9~�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 literal 0 HcmV?d00001 diff --git a/book.toml b/book.toml new file mode 100644 index 0000000..aa8ccfc --- /dev/null +++ b/book.toml @@ -0,0 +1,6 @@ +[book] +authors = ["Xc"] +language = "en" +multilingual = false +src = "src" +title = "Oak Framework 教程" diff --git a/src/SUMMARY.md b/src/SUMMARY.md new file mode 100644 index 0000000..ba49b44 --- /dev/null +++ b/src/SUMMARY.md @@ -0,0 +1,11 @@ +# Summary + +- [Oak 框架简介](./intro.md) +- [开始]() + - [基础知识/开发环境](./chapter1/env.md) + - [创建]() + - [开发](./chapter1/dev.md) + - [部署](./chapter1/deploy.md) +- [框架结构](./chapter2/def.md) + - [entities](./chapter2/entities.md) + - [pages/components](./chapter2/components.md) \ No newline at end of file diff --git a/src/chapter1/deploy.md b/src/chapter1/deploy.md new file mode 100644 index 0000000..f7e62e6 --- /dev/null +++ b/src/chapter1/deploy.md @@ -0,0 +1,3 @@ +# 部署 + +todo \ No newline at end of file diff --git a/src/chapter1/dev.md b/src/chapter1/dev.md new file mode 100644 index 0000000..157e040 --- /dev/null +++ b/src/chapter1/dev.md @@ -0,0 +1,88 @@ +# 编译项目数据结构 +使用Oak框架的项目,需要将项目中数据结构的定义(src/entities目录下),编译成为Oak框架能使用的完整定义(src/oak-app-domain目录下)。当开发人员 +修改了相关数据结构后,也必须执行下述命令: + +```nodejs +npm run make:domain +``` +项目的数据结构编写规范参见:[entities](../chapter2/entities.md) + +# 开发(前台模式) +在Oak框架的设计中,前后端并无区分。在开发模式下,可以将后端逻辑直接运行在前端环境中,使开发过程更加简洁高效。 +前台模式也是推荐的开发模式,可以做到极速的“可见即所得”,编写业务大部分情况下应当使用这种开发模式 + +## 运行web端 +在项目目录下运行 +```nodejs +npm run start:web +``` +运行成功后浏览器会自动打开 +> http://localhost:3000 +即可进行开发调试。推荐使用Chrome浏览器,要注意的是,因为项目只运行在浏览器内部,其数据是和外界隔离的。 + +## 运行小程序端 +在项目目录下运行 +```nodejs +npm run start:mp +``` +运行成功后,用微信开发工具打开wechatMp/dist目录 + +## 运行App端 +Oak的App开发使用react-native技术栈,按照[react-native开发教程](https://reactnative.dev/docs/set-up-your-environment)配置好环境,连接手机后,在项目目录下运行: + +```nodejs +npm run run:android/ios +``` +也可以先运行: +```nodejs +npm run run:bundle +``` +来进行原生安装文件打包,再执行 +```nodejs +npm run start:native +``` +启动react-native调试服务器。 + +# 开发(前后台模式) +如果你的应用开发过程中有以下需求,则需要使用前后台开发模式。 +1. 需要(后端)调用本地的其它应用程序 +2. 需要(后端)访问其它webservice接口 +3. 需要多前端(web + 小程序)同时调试程序 + +## 编译并运行后端 +在项目目录下编译整个项目 +```nodejs +npm run build +``` +编译成功后,在lib目录下是编译后的js代码。 +在项目目录的configuration/mysql.json中编辑本地数据库设置,并执行SQL语句先创建好相应的数据库。 +```sql +create database xxx default character set utf8mb4; +``` +> 当前框架要求使用MySQL 8.0以上版本。 + +再在项目目录下执行: +```nodejs +npm run server:init +``` +初始化数据库。 + +然后执行: +```nodejs +npm run server:start +``` +运行成功后后端服务器启动,并监听在3001端口上。 + +## 运行前端 +在项目目录下执行 +```nodejs +npm run start:web:server +``` +即以前后端模式运行前端部分代码,此时前端会自动请求localhost:3001端口去访问后端服务器。同理,也可以以前后端模式运行小程序 +```nodejs +npm run start:mp:server +``` +要注意的是,如果在前端开发模式和前后端开发模式之间切换的话,需要先清除缓存,以保证切换成功(观察浏览器的Network是否发出请求是确认当前是否成功运行在前后端开发模式下的关键)。清缓存的命令是: +```nodejs +npm run clean:cache +``` \ No newline at end of file diff --git a/src/chapter1/env.md b/src/chapter1/env.md new file mode 100644 index 0000000..647d073 --- /dev/null +++ b/src/chapter1/env.md @@ -0,0 +1,19 @@ +# 基础知识 + +* Oak使用Typescript语言,因此您需要基本掌握: +1. javascript语言基础: [学习资料](https://developer.mozilla.org/zh-CN/docs/learn/JavaScript) +2. Nodejs环境: [学习资料](http://nqdeng.github.io/7-days-nodejs/) [官方文档](https://nodejs.org/docs/latest/api/) +3. Typescript语言基础: [官方文档](https://www.typescriptlang.org/) + +* 在前端,Oak目前使用React作为网页端框架(尽管这不是必须,但由于团队技术力量等原因,短期内没有计划去适配vue等其它框架),因此您也需要掌握React的一些基本概念。如果您需要开发App或者小程序,也需要去了解一些其相关概念。 +1. React: [官方站点](https://react.dev/) +2. React-native [官方站点](https://reactnative.dev/) +3. 微信小程序开发 [官方站点](https://developers.weixin.qq.com/miniprogram/dev/framework/) + +对于其它更多的前端环境,Oak也将在未来进行适配。Oak的前端技术路线请参见:todo + +# 开发环境 + +开发环境只要配置NodeJs 18以上即可,推荐使用Microsoft的Vs Code作为开发IDE +* [NodeJs安装](https://nodejs.cn/download/) +* [VS Code下载](https://code.visualstudio.com/) \ No newline at end of file diff --git a/src/chapter1/script.md b/src/chapter1/script.md new file mode 100644 index 0000000..bca1011 --- /dev/null +++ b/src/chapter1/script.md @@ -0,0 +1 @@ +# 运行项目 diff --git a/src/chapter2/components.bmp b/src/chapter2/components.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4fba8f068be1eda66756d6bccd753008629d094b GIT binary patch literal 11891 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 page之间不要相互引用,尽管这样做也不会错,但会让整个项目变得更加混乱,难以维护。 \ No newline at end of file diff --git a/src/chapter2/components.png b/src/chapter2/components.png new file mode 100644 index 0000000000000000000000000000000000000000..4fba8f068be1eda66756d6bccd753008629d094b GIT binary patch literal 11891 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 + area: Area; + phone: String<12>; + name: String<32>; + default: Boolean; + remark?: Text; + entity?: String<32>; + entityId?: String<64>; +}; +``` + +设计并编写Entity的一些规范如下: +1. 需要用 ```export interface Schema extends EntityShape``` 来定义对象。我们设计Entity时,要么继承*EntityShape*(在其中定义了*id*等几个通用属性),要么继承并扩展已经设计好的对象(在下一小节的*User*对象中你们就可以看到例子), +2. 需要使用 ``` 'oak-domain/lib/types/DataType' ``` 中的类型来声明对象的属性 +3. 可以引用其它Entity,并将之声明为当前Entity的某一属性(此时称之为定义了对象之间的**多对一关系**)。例如在*Address*对象中就声明了*area*属性是代表(地址所属的)地区。 + +> 对象的属性也可以指向其自身。例如,在Area对象的定义中,就有一个 parent 属性指向它自己(Schema),代表该地区的上级地区。 +4. 可以为对象设计动态多对一关系,若一个对象可能和不同的对象有多对一关系,则通过声明 ``` entity: String<32>; entityId: String<64> ```即可以表达动态的多对一关系,即当前对象可能和不同的其它对象具有多对一关系。 + +## 动态多对一关系 +在一些应用中,某对象*A*可能和不同的对象*B/C/D*……具有多对一关系(但这种关系是互斥的,不可能同时和多于一个对象具有这种关系)。此时,如果像这样设计*A*对象: +```nodejs +export interface A extends EntityShape { + b?: B; + c?: C; + d?: D; +}; +``` +显然是一种比较臃肿的方式,同时也不具备良好的扩展性(比方说随着业务的发展,*A*又要指向更多的对象时,必须来修改其Entity定义)。 + +此时可以通过声明两个特殊的属性,告诉Oak框架,此对象可能会指向多个不同的其它对象。 + +```nodejs +export interface A extends EntityShape { + entity: String<32>; + entityId: String<64>; +}; +``` +注意,这里*entity*和*entityId*是类型关键字,您不能拿它们去声明自身对象的其它属性,同时它们的类型也是固定的。 + +回到上面的*Address*对象的例子中,由于*oak-general-business*是较底层的抽象模块,我们想实现*Address*的功能,但并不想限制应用地址对象必须归属于哪个对象(例如,在某个应用系统中,不仅“用户”对象拥有地址,“公司”对象也拥有地址)。 + +问题来了,如何声明当前(拥有动态多对一关系的)对象和其它哪些对象可能有关联呢?只需要在要关联的对象中像下面这样声明就可以了,这里我们引用的代码来自*oak-general-business*中的*User*对象 +```nodejs +import { Schema as ExtraFile } from './ExtraFile'; +import { Schema as WechatQrCode } from './WechatQrCode'; +import { Schema as Address } from './Address'; +import { Schema as User } from 'oak-domain/lib/entities/User'; + +export interface Schema extends User { + passwordSha1?: Text; + birth?: Datetime; + gender?: 'male' | 'female'; + idCardType?: 'ID-Card' | 'passport' | 'Mainland-passport'; + idNumber?: String<32>; + files: Array; + codes: Array; + isRoot?: Boolean; + addresses?: Address[]; +}; +``` +用户这个对象,(以一对多的方式)关联了三个拥有动态多对一设计的对象:*ExtraFile*, *WechatQrCod*e, *Address*。这里我们不去深究其具体含义,只要知道,这三个对象中都设计有 ```entity/entityId``` 属性,同时我们在User对象的定义中声明了,User和它们具有一对多关系。这里用*Array*和[]的写法都是可以的。 + +> 如果一个对象想拥有超过一个的动态多对一关系怎么办?很遗憾,Oak并不支持这种设计。而且根据我们的经验,在实际应用开发中,出现如此复杂的对象往往意味着你应该重新审视你的对象设计是否合理了。 + +## 更多属性相关 +Oak当前支持的基本属性类型可以参见:```oak-domain/lib/types/DataType```。 +> 其中,*Float*和*Double*类型已经不再推荐,请尽量使用*Decimal*来定义非整型数值 + +除去这些类型之外,Oak还支持: +* 以枚举的方式定义。例如在上一小节中*User*的*gender*属性 +* 以对象的方式定义。如果某个属性非常复杂,不能用基本类型表示。你既可以定义其为*Object*,也可以用TS来定义其具体格式 + +以下代码节选自*oak-general-business*的*Application*对象。每个*Application*对象代表着系统的一个应用(Web/小程序/App……),因此它需要丰富的配置信息。 +```nodejs +export type AppType = 'web' | 'wechatMp' | 'wechatPublic' | 'native'; + +export type NativeConfig = { + type: 'native', + passport?: Passport[]; +}; + +export interface Schema extends EntityShape { + name: String<32>; + description: Text; + type: AppType; + system: System; + config: WebConfig | WechatMpConfig | WechatPublicConfig | NativeConfig; + style?: Style; + sessions?: Session[]; + domain?: Domain; +}; +``` +在这里,*type*属性指向了一个枚举类型,*config*属性和*style*属性都指向更复杂的对象,*config*对象甚至指向一个复杂对象的枚举。 + +## Action和State +在应用中的一些对象(核心业务对象),往往具有**状态**的概念。通过在Entity中定义其状态和**动作**,以及两者之间的关系,可以使应用更加严谨和可维护。 + +以上面所提到的 *oak-general-business* 中的*User*对象为例,在我们的设计中,用户这个对象有两种状态的转变: +1. 对象状态:分为四种:*正常用户/被禁用用户/被合并用户/影子用户*。在这里我们不去深究后面两种的语义,只需要知道这代表着*User*的状态可能发生变化。比如说如果发现某个用户经常违规,管理员可以将之禁用,此时用户就变成了被禁用状态,将无法再登录系统。 +2. 对象身份状态:有的应用需要验证用户的真实身份,此时用户的身份状态就有三种:*未认证/认证中/已认证* + +很显然这两种状态的转变是彼此独立的,我们可以通过以下的声明代码,来规范这两种状态。除了状态之外,我们也可以定义对*User*这个对象可能的动作,来规范状态的转变(以及后面的权限管理)。 +```nodejs +export type IdAction = 'verify' | 'accept' | 'reject'; +export type IdState = 'unverified' | 'verified' | 'verifying'; +export const IdActionDef: ActionDef = { + stm: { + verify: ['unverified', 'verifying'], + accept: [['unverified', 'verifying'], 'verified'], + reject: [['verifying', 'verified'], 'unverified'], + }, + is: 'unverified', +}; + +export type UserAction = 'activate' | 'disable' | 'enable' | 'mergeTo' | 'mergeFrom'; +export type UserState = 'shadow' | 'normal' | 'disabled' | 'merged'; +export const UserActionDef: ActionDef = { + stm: { + activate: ['shadow', 'normal'], + disable: [['normal', 'shadow'], 'disabled'], + enable: ['disabled', 'normal'], + mergeTo: [['normal', 'shadow'], 'merged'], + mergeFrom: ['normal', 'normal'], + }, +}; + +export type Action = UserAction | IdAction; +``` +在这里,我们声明了两组状态和动作,以及状态转换矩阵,同组中的状态/动作/转换矩阵的前缀必须要一致。状态转换矩阵规定了某个*Action*将把*User*的当前(对应的状态值)修改成什么,这种转换在规定之后应当是一目了然的。其中,```is```定义的是初始状态(若对象创建时没有赋初始状态则默认使用这种状态值)。 + +最后,我们通过``` export type Action ```来声明了当前对象上的所有*Action*。对当前对象的操作将被限制在这些自定义的*Action*和通用的*Action*当中。通用的*Action*包括: +* create +* update +* remove +* select +* count +* download +* aggregate +* stat + +在定义您自有的*Action*时请避免使用这些关键字。 + +> *Action*是否必须与*State*相关联?并不是,完全可以定义某个Action并不改变对象的状态,甚至不改变对象本身的任何属性!实际上,我们鼓励根据应用的需求,尽量细的划分不同动作,以便实现更好的程序严谨性和权限管理。某种意义上,可以将自定义的*Action*看成一种特殊的*update*。 + +## Relation +几乎所有的应用系统都有一个共同的核心对象——用户。用户就是使用应用系统的人,而应用系统要对用户使用应用系统的行为加以甄别和管理(权限分配和限制),前提就是要将系统中的业务对象“分配”给合适的用户。*Relation*所表达的,就是当前对象和用户的**关系**。 + +如果一个对象和用户具有Relation,则可以像下面一样定义,下面的代码节选自*oak-general-business*中的*Session*对象定义。 +``` +export type Relation = 'partner'; +``` +*Session*对象代表的是一个会话,而*partner*关系表达的就是参与这场会话的人。如果一个*User*和一个*Session*存在*partner*关系,则代表这个用户参与了这场会话。 + +#### Relation的底层实现 +在*oak-domain/src/entities*中,定义了一些公共对象,这些对象存在于所有的Oak项目中(尽管或许个别项目不会用到它们全部)。其中有一个对象*UserRelation*,其代表的就是用户和某个对象之间的*Relation*。 +```nodejs +import { Schema as User } from './User'; +import { Schema as Relation } from './Relation'; + +export interface Schema extends EntityShape { + user: User; + relation: Relation; + entity: String<32>; + entityId: String<64>; +}; +``` +如果你理解了本章的内容,应当能理解*UserRelation*对象中各个属性的含义了吧。😁 + +## EntityDesc +最后,我们需要为我们所有定义的内容进行描述。描述的目的有两个: +1. 使此对象上的一些命名和风格全局一致(例如对象命名、对象属性命名等) +2. 使此对象在存储时得到优化 + +对对象进行描述的代码如下面这样,我们仍然使用*oak-general-business*对象中的*User*对象举例: +```nodejs +export const entityDesc: EntityDesc< + Schema, + Action, + '', + { + userState: UserState; + idState: IdState; + gender: Required['gender']; + idCardType: Required['idCardType']; + } +> = { + locales: { + zh_CN: { + name: '用户', + attr: { + name: '姓名', + nickname: '昵称', + birth: '生日', + password: '密码', + passwordSha1: 'sha1加密密码', + gender: '性别', + idCardType: '证件类型', + idNumber: '证件号码', + ref: '指向用户', + files: '相关文件', + userState: '用户状态', + idState: '认证状态', + codes: '微信分享二维码', + isRoot: '是否超级用户', + addresses: '收货地址', + }, + action: { + activate: '激活', + accept: '同意', + verify: '认证', + reject: '拒绝', + enable: '启用', + disable: '禁用', + mergeTo: '合并', + mergeFrom: '使合并', + }, + v: { + userState: { + shadow: '未激活', + normal: '正常', + disabled: '禁用', + merged: '已被合并', + }, + idState: { + unverified: '未认证', + verifying: '认证中', + verified: '已认证', + }, + gender: { + male: '男', + female: '女', + }, + idCardType: { + 'ID-Card': '身份证', + passport: '护照', + 'Mainland-passport': '港澳台通行证', + }, + }, + }, + }, + indexes: [ + { + name: 'index_birth', + attributes: [ + { + name: 'birth', + direction: 'ASC', + }, + ], + }, + { + name: 'index_fulltext', + attributes: [ + { + name: 'name', + }, + { + name: 'nickname', + }, + ], + config: { + type: 'fulltext', + parser: 'ngram', + }, + }, + { + name: 'index_userState_refId', + attributes: [ + { + name: 'userState', + }, + { + name: 'ref', + }, + ], + }, + ], + style: { + icon: { + verify: '', + accept: '', + reject: '', + activate: '', + enable: '', + disable: '', + mergeTo: '', + mergeFrom: '', + }, + color: { + userState: { + normal: '#0000FF', + disabled: '#FF0000', + merged: '#9A9A9A', + shadow: '#D3D3D3', + }, + idState: { + unverified: '#FF0000', + verified: '#0000FF', + verifying: '#EEE8AA', + }, + gender: { + male: '#0000FF', + female: '#EE82EE', + }, + idCardType: { + 'ID-Card': '#E0FFFF', + 'Mainland-passport': '#2E8B57', + passport: '#2F4F4F', + }, + }, + }, +}; +``` +在对象描述的类型定义*EntityDesc*中,可以传入四个参数,分别是对象定义*Schema*,对象动作定义*Action*,对象关系定义*Relation*,以及对象的相关状态和枚举属性定义字典。而对对象描述中,主要有: +* locale定义,对对象本身/属性/属性枚举值/状态/动作/关系进行命名,这里的命名将被Oak框架编译成i18n的数据,实现全局命名的一致性(对编写优秀的应用极其重要!) +* indexes定义,定义相关索引项。在这里定义的索引会在数据库建立的时候自动创建,也会规范对对象的查询方式(例如如果没有声明全文索引,则无法进行全文搜索) +* style定义,定义对象的动作/关系/状态的颜色和图标(尚未实现),使前端渲染时可以获取相应的颜色,以实现颜色的全局一致性(同样对编写优秀的应用极其重要!) + +由于TS的优秀的规范性,这里的定义如何详细书写不再赘述。 + +## Entities的作用 +Entity的定义可以说是整个应用业务的核心,通过执行 +```nodejs +npm run make:domain +``` +Oak框架会在```src/oak-app-domain```目录下编译出完整的应用对象定义,这份定义既包括开发人员编写代码时的Typescript类型定义,也包括程序运行过程中访问对象时的正确性检查。因此请牢记: + +1. **对Entity的任何修改都应当执行 npm run make:domain,使修改后的定义生效** +2. **如果应用已经上线迭代,对Entities目录下的任何修改,都应当在upgrade目录下维护好对数据库(结构或数据)的升级脚本,新版本上线时进行升级** \ No newline at end of file diff --git a/src/env.md b/src/env.md new file mode 100644 index 0000000..92d9aaf --- /dev/null +++ b/src/env.md @@ -0,0 +1 @@ +# 基础知识/开发环境 diff --git a/src/intro-1.png b/src/intro-1.png new file mode 100644 index 0000000000000000000000000000000000000000..43707ae1fc3fec7e06018c420c99a46c1f32e75b GIT binary patch literal 16030 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 BD)s;X literal 0 HcmV?d00001 diff --git a/src/intro.md b/src/intro.md new file mode 100644 index 0000000..52f3bf2 --- /dev/null +++ b/src/intro.md @@ -0,0 +1,36 @@ +# Oak框架简介 + +Oak是一个现代的应用系统快速开发框架,它实现了对业务系统相对抽象层次上的功能抽象,使应用开发者可以将自己的注意力完全集中于实现业务逻辑本身,而无须关注众多构建应用系统需要考虑的(共性)问题,例如: + +* 我该选用什么样的数据库,如何建立索引? +* 我该怎样设计并实现全局一致的用户权限?(几乎没有多少应用系统能完美解决这一问题) +* 我该怎样设计前后端接口才能保证低耦合且可重用?(传统MVC设计模式下controller如果不加以规范的组织设计/定期重构,对于长期开发而言是一场灾难) +* 我该如何在各层次上保证数据的一致性?(前端->后端->分布式,每一个层面上都有各种细节问题需要考虑) +* 我该如何保持前后端常量和逻辑的一致性?(有很多库被设计专门用来解决这一问题,使得整个项目变得更加复杂) +* 我的应用如果有多个前端,如何在代码复用和保证高可持续开发性之间取得平衡? +* 如何发现并杜绝我的项目在各个层次上的安全漏洞? + + +## Oak的背景与目标 + +作为软件开发者,在当今这个年代要开发业务软件既是幸福的也是痛苦的。一方面,众多成熟的技术方案及SaaS类服务几乎能解决应用开发中遇到的各种问题(对比20年前,光是一个图片上传预览就要手写解决无数的问题),另一方面,开发软件需要不断学习和使用的新技术/开源库也越来越多,甚至可以说,几乎没有人的学习速度能赶得上新技术的出现速度。技术栈的爆炸既造成了应用开发者之间的鸿沟(我的项目代码只有我能维护的动😭),也让绝大多数小团队或者个人开发者难以赋予项目一个健壮、可持续的基础架构。当一个项目持续开发一年以上,代码往往就成为了著名的“屎山”。 + +Oak框架的设计目标就是解决软件开发过程中的这些问题,让现代典型的应用系统开发达到一致、可持续、高可用的目标。 + +## Oak的技术选择 + +Oak框架使用[Typescript](https://www.typescriptlang.org/)作为开发语言。Oak设计之初就希望以一种语言统一编写前后端(前后端一致性),让团队中编写应用的程序员变成“完全对等”的。在此前提下,Javascript语言几乎是唯一的选择。同时为了提高代码的规范性,当前最流行的Typescript成为了我们的选择。 + + +> Typescript语言在开发过程中非常消耗计算机资源,请确保您的开发机器拥有Intel 12代以上的Cpu以及16GB以上的内存空间,以获得较好的开发体验😁 + +Oak框架主要针对项目的整体架构及公共功能抽象,其本身并没有限制过多的技术栈。例如,后端数据库默认使用MySQL,但您也可以通过编写一些适配性的代码来使之运行在PostgreSQL或者MongoDB之上;在前端,目前我们选择使用React,但这也并不意味着您不能使用vue(当然,这需要您自己实现一套vue上对等的逻辑转换)。在未来,我们将积极拥抱开源,希望集各方之力,服务于数量广大的应用开发工程师。 + +## Oak的定位 +纵观计算机软硬件技术的发展历史,都可以用“抽象”两个字来概括,例如,操作系统就是对各种硬件的抽象,数据库就是对于数据存储查询的抽象。从这个角度看,Oak框架也是一种抽象,它是最接近业务层次的抽象,尽可能的将业务需要遇到的各种共性问题统一进行了处理,并制订了业务逻辑编写的开发规范,以致力于**使业务开发者不写一行多余的代码**这一目标。 + +![Oak定位](./intro-1.png) + +需要强调的是:**正如操作系统和数据库一样,Oak也并非能解决所有的应用开发问题,它的设计目标仅仅是为了提高应用软件开发的效率和规范。一名优秀的工程师仍然应当掌握更多基础技术的实现,以应付项目中的更多问题**。 + +Oak仍然在不断开发完善中,如有问题,也欢迎加入讨论小组,给出您的宝贵建议。