Skip to content

Commit e3e64ad

Browse files
committed
cn update
1 parent 62d62c2 commit e3e64ad

File tree

1 file changed

+21
-23
lines changed

1 file changed

+21
-23
lines changed

readme-cn.md

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
构建面向视图的数据时, 不可避免会出现数据拼接的场景. 根据视图数据的复杂程度, 拼接的难度会有很大的差异.
44

5-
三层的数据拼接会比两层的复杂, 四层的肯定会更加麻烦.
6-
75
```json
86
[
97
{
@@ -39,11 +37,11 @@ for t in teams:
3937
...
4038
```
4139

42-
过程式的数据处理对调整和阅读都不友好, 循环和拼接容易产生不通用且不易维护的代码. ORM 则存在使用场景的约束.
40+
过程式的数据处理对调整和阅读都不友好, 循环和拼接容易产生不通用且不易维护的代码. 添加和修改也很麻烦.
4341

44-
GraphQL 带来的通过声明描述数据结构是一个好的方向, Graqph Query Language, 作为一种声明式的查询语言, 扮演的是一系列特定资源的获取和组合. 从定位上来说, GraphQL 用来给项目的前端提供数据是一种错误的用法, 它的定位和 SQL 是类似的, 为服务端获取数据提供便利. 并且可以尽量不用考虑权限, 限速等问题.
42+
GraphQL 带来的通过声明描述数据结构是一个好的方向, Graph Query Language, 作为一种声明式的查询语言, 服务于一系列特定资源的获取和组合. 从定位上来说, GraphQL 用来给项目的前端提供数据其实是一种错误的用法, 它的定位和 SQL 是类似的, 为服务端获取数据提供便利. 并且可以尽量不用考虑权限, 限速等问题.
4543

46-
一段复杂的GraphQL query 和一段复杂的 ORM SQL 的定位是类似的. 在获取到了需要的固化数据之后, 再通过任意一种协议, 比如 http, 比如 rpc 等方式传递给前端使用. 前端作为展示层, 被动地使用后端接口数据即可. 现在很多前端直接使用 GraphQL 来组合查询, 从职位划分来说做的是一部分后端的工作. 把GraphQL 放在 client 和 server 之间并不是一个理想的定位. 就像把 SQL 查询暴露给 client 一样.
44+
一段复杂的GraphQL query 和一段复杂的 ORM SQL 的功能很相似, 只是GraphQL更擅长组合数据. 在获取到了需要的视图数据之后, 再通过任意一种协议, 比如 http, 比如 rpc 等方式传递给前端使用. 前端作为展示层, 被动地使用后端接口数据即可. 现在很多前端直接使用 GraphQL 来组合查询, 从职位划分来说等于插手了一部分后端的工作. 把GraphQL 放在 client 和 server 之间并不是一个理想的定位. 就像把 SQL 查询暴露给 client 一样. (对数据的管理分散在多个环节不利于项目维护.)
4745

4846
GraphQL 的思路是通过 Query 确定最终的查询结构, 一层层驱动后端的 resolver 来构造数据.
4947

@@ -52,15 +50,18 @@ GraphQL 的思路是通过 Query 确定最终的查询结构, 一层层驱动后
5250
- 无法描述尺寸不确定的递归结构
5351
- key 不确定的 Dict 结构
5452
- Query 比较复杂的话, 性能问题不容易优化.
55-
- 无法对查询到的数据做比较精细的后期处理 (middleware 的入口是query 数据的顶层)
53+
- 数据的后处理不方便
54+
- 要使用它定义的一套类型
5655

5756
等等.
5857

59-
总结来说, GraphQL 在提供了视图数据方面, 有查询灵活度高的优点, 同时存在获取的数据后期调整比较麻烦, 以及架构侵入较大等缺点. 比如 GraphQL 获取到多层数据后要做层级聚合统计, 就需要重新便利一遍树状数据来处理. 框架本身没有设计合适的下层数据处理完之后触发回调的钩子.
58+
总体来说, GraphQL 在提供视图数据方面, 有查询灵活度高的优点, 但存在获取的数据后期调整比较麻烦, 以及架构侵入较大等缺点. 比如 GraphQL 获取到多层数据后要做层级聚合统计, 就需要重新便利一遍树状数据来处理. 框架本身没有设计合适的下层数据处理完之后触发回调的钩子. (这恰恰是对视图调整很有用的)
59+
60+
思考后会发现, 其实我并不需要GraphQL 那个灵活的查询组合功能. 在处理视图数据的时候, GraphQL 最大的启发是他申明式的数据描述方式.
6061

61-
稍加思考会发现, 我并不需要GraphQL 那个灵活的查询组合功能. 在处理视图数据的时候, GraphQL 最大的启发是他申明式的数据描述方式.
62+
以 graphene-python 为例, Query对象可以支持灵活的 GraphQL 查询, 比如挑选字段, 或者重命名等等.
6263

63-
以 graphene-python 为例:
64+
并且随着功能的添加, Query 里面会增加越来越多的内容.
6465

6566
```python
6667
from graphene import ObjectType, String, Schema
@@ -75,17 +76,13 @@ class Query(ObjectType):
7576
def resolve_goodbye(root, info):
7677
return 'See ya!'
7778
schema = Schema(query=Query)
78-
```
7979

80-
这样的Query对象可以支持灵活的 GraphQL 查询, 比如挑选字段, 或者重命名等等.
81-
82-
```python
8380
query_with_argument = '{ hello(firstName: "GraphQL") }'
8481
result = schema.execute(query_with_argument)
8582
print(result.data['hello'])
8683
```
8784

88-
那如果我并不需要去查询, 而是直接把 Query对象直接就作为标准视图结构呢?
85+
那如果我并不需要去编写查询, 而是直接把 Query 直接当成一个描述语句来使用呢? 那我不就省下了额外描述的成本了?
8986

9087
```python
9188
from pydantic import BaseModel
@@ -107,7 +104,7 @@ async def main():
107104

108105
面向 schema 进行定制化的描述. 借助 pydantic 强大的类型转换和检查的功能, 来实现申明式的数据结构描述.
109106

110-
优点就是把大而全的单一查询入口, 替换成了一个个小巧灵活的定制化 schema 描述.
107+
**优点就是把大而全的单一查询入口, 替换成了一个个小巧灵活的定制化 schema 描述.**
111108

112109
> 基于 schema 的声明式描述让整个结构摆脱了 GraphQL 的架构约束, 只用常用的 type annotation 就把定义给实现了.
113110
>
@@ -116,19 +113,22 @@ async def main():
116113

117114
## 什么是面向组合的模式?
118115

119-
面向组合的开发模式就是在这个简单case 的基础上, 扩展的一套开发模式. 核心概念就是在`根数据`的基础上, 通过一层层定义需要的扩展字段, 然后交给 `Resolver` 来填充所有的数据.
116+
面向组合的开发模式就是在这个简单例子的基础上, 逐步扩展出来的一套开发模式.
120117

118+
核心概念就是在`根数据`的基础上, 描述每一层需要的扩展的字段和查询方式, 然后交给 `Resolver` 来填充所有的数据.
121119

122120
罗列一下, 这套开发模式有以下这些能力:
123121

124122
- 可以方便的描述组合体数据的 schema, 然后resolve出完整数据, 定义方式简单 (借助 pydantic or dataclass)
125-
- 任意深度, 任意类型.
126-
- 读取全局参数, 读取祖先节点数据
127-
- 每层 `resolve` 完子孙数据后, 有 post 方法来操作数据
123+
- 任意层级, 任意类型.
124+
- 可以读取全局参数, 可以跨层级向下传递数据
125+
- 每一层都有后处理数据的能力
128126
- 可以挑选所需的字段
129127
- 解决 N+1 查询相关的性能问题
130-
- 各个 service 仅需提供通用的 loader, 用于数据拼装
131-
- 保证前后端对修改的感知能力, 易于修改重构 (借助OpenAPI)
128+
- 架构简单, 各个 service 仅需提供通用的 loader, 用于数据拼装
129+
- 借助OpenAPI, 前端对后端操作简化为sdk 方法调用.
130+
- 调整视图数据很容易, 让前端真正做到开箱即用.
131+
- 对优化友好, 只要保证输出一致, 内部重构对API使用者无感.
132132

133133

134134
> 可以很容易联想到, 我们获得了一个 API 提供一个page 所需数据的能力, 这会让前后端接口关系变得更简单.
@@ -198,8 +198,6 @@ Mini jira 包含了常见的敏捷开发中的各种概念和其之间的关系.
198198

199199
只需要描述好 Task 要扩展的字段, Story 要扩展的字段, 然后 Resolver 就会帮你处理完后续的所有事情.
200200

201-
修改调整都变得非常简单轻松.
202-
203201
```python
204202
from typing import Optional
205203
from pydantic2_resolve import LoaderDepend as LD

0 commit comments

Comments
 (0)