V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  crclz  ›  全部回复第 32 页 / 共 35 页
回复总数  684
1 ... 24  25  26  27  28  29  30  31  32  33 ... 35  
2019-11-20 16:22:59 +08:00
回复了 StarkWhite 创建的主题 程序员 GraphQL 在 HTTP/2 世界中仍然有意义吗?
NoSQL 能避免 Chatty 的通信,消除累计的往返延迟(一次往返 vs n 次往返)。这是一个很重要的点。

但是,更重要的是,GraphQL 让数据的请求的粒度更加细化:一个实体,一个请求。例如,我查询了一个订单信息,订单有多个商品。大部分 GraphQL API 会被设计成向数据库发起多个查询,分别获取商品,或者先获取商品 id 数组,再 batching ;而不是关联查询。在传统的架构下,这是性能的浪费。但是如果假如有 redis 缓存,那么这种细粒度的设计就赋予了向 redis 查询数据的能力:拿到商品 id 数组后,先查 redis。

当然,这种细粒度的设计也简化了查询接口的开发,降低了前后端的协调成本,这我觉得是非常重要的点。
先学老技术:看官方文档(如果文档像 docs.com 一样优秀的话),并完整的进行实践。工程、实践量一定要够。
感觉老技术的不足:你感觉哪里不爽?并试图解决部分问题,例如写一个不完美的小的框架。
学习新技术,看官方文档,想:它解决了老技术的什么问题?和你的框架比起来有啥优势?
2019-11-17 00:18:45 +08:00
回复了 miv 创建的主题 程序员 求助,如何写这种业务 sql 比较好
题目描述太少。隐隐约约感觉表 B 设计的有问题啊。

机构编码 | 机构名称 | 父级机构编码
- - -
1007、广州、100
10078、天河某区、100

这两行属于相同的业务概念?
2019-11-17 00:08:56 +08:00
回复了 rizon 创建的主题 程序员 apkdownloader 下载的 app 与官网不一致,是否是篡改?
@rizon 先安装某个,再安装另一个。如果签名是一样的,那么 可能 就会有提醒。
2019-11-16 23:54:15 +08:00
回复了 Simle100 创建的主题 Java 方式 1 和方式 2 的却别到底在哪里?
关于业务代码的错误处理,我的理解:
封装好的业务逻辑方法( HelperClass, Utils ),应当返回一个 Result。这个 Result 可以组织成这个结构:
{
ErrorCode String
Data Dictionary<string, string>
}
ErrorCode:用于给前端传递约定好的错误代码,例如'NicknameAlreadyExist'。
Data:用于给前端传递进一步细化错误的数据。例如前端传过来一个请求,要转账 400 元。你和前端约定,如果不足 400 元,为了告诉用户更多信息,就将它的余额{money: 300}加在 data 里面。
还可以设置一些字段支持多个错误代码,但我觉得大部分时间没必要。
还可以设置一些字段来告诉 http 请求发起者更多信息,详见各大 api 规范,例如 https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md
还可以设置一些字段来储存调试信息,这些信息可能会帮助到你再看错误日志的时候快速 debug。

但是,这样做有几个需要注意到的要点。

这样设计 HelperMethod 实际上是 Try-Parse Pattern。

HelperMethod 可能会被直接拿去用,也可能会被 HelperMethod 嵌套使用。当直接用的时候,调用者相当于客户端。当被其他 HelperMethod 嵌套调用的时候,大部分情况是像 GoLang 一样返回。也还有其他情况,例如:在方法 A 中,我调用方法 B。方法 A 的代码已经对一些条件进行了数据库的查询、检查。这些检查,可能碰巧的涵盖了方法 B 的检查。所以,方法 A 此时认为,对 B 的调用是一定会返回 success 的。所以如果返回了一个 error,那么就应当直接抛出异常(或者在 error 里附带这一层的某些有助于调试的信息),Exception.Data 里面附带这个 error。这很自然,因为这个内层的 error 不该返回给前端,因为用户会对这个 error 里面的内容可能会不知所云。
异常抛出了,然后被你的 http 框架( spring/WebApi )捕获,然后被你的 logger 记录。你去看 log,里面你记录的调试信息就可能会帮助你还原问题,尽快 debug.

---

跳出异常的话题。HelperClass 虽然被广泛使用,但有很多弊端。
在性能上,可能重复查数据库很多遍,检查某个条件。
在开发效率上,会出现领域知识的割裂、分散;持久层逻辑的污染;健忘。DDD 是解决方案。
2019-11-16 23:16:36 +08:00
回复了 Simle100 创建的主题 Java 方式 1 和方式 2 的却别到底在哪里?
@wysnylc 发出几个异常收藏的文章的链接。我顺便给大家概括一下。

##A
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing
这是微软的关于如何设计 library ( framework design guideline )的电子书的一个章节。注意看左边子目录里面共有 4 篇关于异常的文章(第一篇是简介)。
注意这是关于如何设计 library 的文章,其中大部分东西可以适用于业务上,例如 test-doer 模式、try-parse 模式;而某些条条框框不能套在业务代码上面,例如 "DO NOT use error codes" 。
当然,关于 library 使用异常还是 go 风格的东西(error codes),还需要深入研究。不过已知的是,java/c#的东西久经检验,不会差。

另外,如果心存疑问的话,可以去 GitHub 上面 clone 一下 CoreFx (.net core 标准库)的代码。我简单的看了少部分,发现:
1. 大部分 throw 代码,抛出的都是 ArgumentException (ArgumentException, ArgumentNullException, ArgumentOutOfRangeException),还有 InvalidOperationException。为什么会这样呢?答案很自然:因为出了问题,问题肯定在 caller 的传参上面,或者在 [当前对象的状态不合适] 上面。正如 C# Docs 所言,InvalidOperationException is used in cases when the failure to invoke a method is caused by reasons other than invalid arguments.
2. 这些异常的抛出都是这样抛出的 if(argument x not satisfy some condition) throw ArguementXXXXXException. 并且每个函数开头几乎都会检查所有参数。(这很自然。记住这样做也是标准做法。)
3. 很少能看见捕获异常的代码。所以不要动不动就捕获异常。总而言之,你的 library 和业务都应几乎不出现 catch。这些东西你都不用关心。想一想 catch 了也没啥用。
4. 小部分捕获异常的代码,几乎捕获的都是 InvalidCastException 之类的. InvalidCastException 是由于失败的转换类型抛出的。这都是在架构里面属于有点底层的东西,可能某些东西设计不当,我也没深究,平时应该不会碰到。
5. 我也看了 EntityFrameworkCore 的代码。发现,也不能说完全不用 catch 吧。EF 的 catch 还涉及到这样的东西:捕获 - 记录(log) - rethrow。如果你有这样做的需求,你可以这样做。
6. 捕获异常的操作还可用于:(节选自 docs of Exception.InnerException )“你可以创建一个新的异常来捕获更早的异常。 处理第二个异常的代码可以利用以前异常中的其他信息来更正确地处理错误。”。 我的评论:EFCore 也有少量这种代码,但是平时会很少有这种应用场景。设计 Library 的时候,如果你想要捕获异常后加点料,也可以加在 Exception.Data 属性。docs of Exception.Data: "to store and retrieve supplementary information relevant to the exception"。
7. 内层的不恰当设计(或者天生的缺陷),会影响外层的代码。这很好理解:如果业务 HelperClass 使用异常来返回错误代码,那么外层的代码也会被迫用这种愚蠢的方式写组织代码。第二,何谓天生的缺陷?我的理解是"互操作"的天生不足。你去调用一个其他语言的东西(例如 c 语言的),这些东西和契合的本来就不如当前语言好。

## B 和 C
这两篇文章能加深对异常处理的理解。
http://www.informit.com/articles/article.aspx?p=433387
https://enterprisecraftsmanship.com/posts/error-handling-exception-or-result/

## D
https://martinfowler.com/articles/replaceThrowWithNotification.html
我直到刚才,才发现,这篇文章是 Martin Fowler 写的!!!!!
它讲了 Validations (验证输入)时应该以 Notification 的方式(类似于一个 Result Class,或许可以将业务的 result class 和这个结合起来)。主要场景大概是处理 http 接口传入的参数。( ModelValidation )
2019-11-16 15:38:27 +08:00
回复了 Simle100 创建的主题 Java 方式 1 和方式 2 的却别到底在哪里?
别信楼上大多数人的。团队的代码质量就是被他们败坏的。
[关于异常的收藏文章]( https://i.loli.net/2019/11/16/cMDWxm67A9bRYHI.jpg)
这些文章很有必要读。

不想看文章可以看结论:

分成写 library 和写业务代码。
写 library 时检查参数+抛出异常( go 另说)+几乎不捕获异常。
写业务的时候因为前端所接收到的返回内容是业务逻辑层决定的,所以对业务逻辑的封装成的 utils/helper-class/transactional-script 的大部分方法应当使用 XXXResult 作为返回对象。当然这个 XXXResult 怎么设计又是一门学问。不过别嫌烦。golang 都不嫌烦。
写业务的时候也要检查参数,抛出异常,例如字符串为 null 的时候,显然是代码哪里有问题。这都是要和调用者有一定约定(文档)的。

例外:数据库插入的唯一冲突。数据库插入冲突只能由数据库底层机制避免,而不是简单的参数检查。所以这里可以适当捕获异常。更好的做法是 upsert ( ON CONFLICT DO NOTHING RETURNING id )
2019-11-16 15:11:10 +08:00
回复了 HTSdTt3WygdgQQGe 创建的主题 程序员 请问 Python 爬虫,配合什么数据库效果最佳
只写过玩具爬虫。一点其他领域得来的拙见:如果存储空间够的话,postgres 的插入速度完全够用:用 N+1 个线程,N 个线程往 1 个 queue 里面写数据,1 个线程定期( 100ms )将数据 bulk insert 到数据库。普通的 insert 可能吃力。
也建议了解 Cassandra。
mongo 可能速度不够用。
2019-11-16 07:58:10 +08:00
回复了 rqxiao 创建的主题 程序员 给数据库字段添加唯一性的字段约束有什么弊端吗
代码判断(×),代码判断+唯一索引(×),唯一索引(√)

我来解释一下。代码判断无法完全避免键冲突的并发。而不管有没有代码判断,数据库内部都会再做一次唯一性的判断。所以如果使用两者的话,会多一层性能损失。
可以使用捕获异常,或者更规范一点,postgres 的 insert ... on conflict(条件) do nothing returning id,再判断 id 是否为 null。mysql 的不知道怎么做。


@mcfog 做数据库模型变更,一地鸡毛,只能说明开发水平不够高。避免一地鸡毛的方法就是在领域层和基础设施层之间加一层转换层。或者传统的项目在 orm 里面改代码,让数据库迁移不过多“污染”业务代码。这层转换层一方面能保持原来的业务代码不需要更改,一方面在保存数据时如果发现是旧的数据模型,则附带做数据迁移。
@areless 你还是没搞清楚何时使用 mongo 这类的 nosql,何时要使用传统的 sql。基于脆弱的知识,一切推论都是白搭(有点像民科)

sql 属于万精油型:由于其粒度小,所以干小规模的事情,都不会很差。
mongo 因为其数据粒度大,所以适合分布式。并且,由于现在的大部分业务场景中,数据的粒度都很大,所以即使单机,mongo 也有速度优势。

何谓粒度大? sql 的粒度很小,要获取一个业务操作所需要的数据,需要到很多不同的地方取数据。磁盘随机 IO 负担重,甚至一次操事务会涉及好几台机器,甚至是分布在不同地域的机器。mongo 则相反,在设计文档结构的时候可以挑选适合自己业务的数据粒度,可以将高频使用的东西聚合在一起,这样大多数事务只会涉及到一个文档。

内存再快,遇到网络延迟,尤其是 sql 需要从几个不同的服务器上面取数据、加锁、判断每份数据的改变是否传播到了特定数量的节点,响应时间和吞吐量都很差。
2019-11-14 19:24:13 +08:00
回复了 oldbird 创建的主题 Python cpu 主频低, Python 处理慢?
看看任务管理器资源占用
2019-11-12 21:27:02 +08:00
回复了 ayonel 创建的主题 Java 老哥们,周二好。问一个跨库保证一致性的问题
普通解决方案:
表的字段设置一个 UpdatedAt,一个 CreatedAt。写一个脚本,定期( maybe 0.1s )将新插入的记录或者修改的记录刷写到在 neo4j 中。同时在 neo4j 中记录这张表上次刷到哪个时间戳了,下次就从这个开始。注意时间戳的精度问题:java,c#的精度会和数据库中的不一样,会出大问题。所以就应该用 int64 存 UtcTicks。

进阶的:
这其实就是一主多从中的复制。看看有没有一个实用性广的解决方案,避免自己写过多的复制逻辑。

最高级的:
采用 CQRS+事件溯源。业务通过事件的形式写入(持久化的)消息队列。需要单独的程序根据事件定期增量式刷新物化视图(主要的)、更新某些(可能更加 denormalized 的)用于加速查询的数据库(例如 redis,neo4j )。
缺点:实现复杂,并且业务多多少少需要一些强一致性来简化开发。
@chocotan 不用了。它们会录键盘。
@exceptionplayer1
首先建议考虑邻居的感受。
我高三的时候也神经衰弱了一段时间。挺难受的。我们楼上走动、打电话(吼大声)、冲厕所都听的到。那时候我还不知道耳塞这个东西。不过熬过来了。
如果你的走路的方式不对的话,或是拖鞋有点特别的话,走路也会听得见。关门也一定要慢关。
最简单的方法就是去他家实地听一下:你家里人在楼下听,然后你进行关门、走路等活动。然后你去下面听,家里人在上面模拟活动。

@korokke 安耳悠是真的行!!!

@lijunnan 3M 冬天可以,夏天塞不进去。
2019-11-09 00:10:33 +08:00
回复了 Zink99 创建的主题 程序员 能推荐一些书吗?
《技术内幕》
2019-11-09 00:08:13 +08:00
回复了 lunar96 创建的主题 问与答 我一女生,睡觉打呼,怎么破
@encro 运动后会减轻 那是因为运动后免疫力下降
2019-11-08 10:06:41 +08:00
回复了 daijinming 创建的主题 程序员 dotnet 开发 API 的时候使用 asyn 、await 有什么优势吗
@loqixh 网上我看过一些评测,发现都是 go (的某个框架)优于.net core
2019-11-08 01:01:13 +08:00
回复了 daijinming 创建的主题 程序员 dotnet 开发 API 的时候使用 asyn 、await 有什么优势吗
@xingheng @xuanbg 回复一直发不出来,截断后发出来了。
1 ... 24  25  26  27  28  29  30  31  32  33 ... 35  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   944 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 34ms · UTC 21:59 · PVG 05:59 · LAX 13:59 · JFK 16:59
Developed with CodeLauncher
♥ Do have faith in what you're doing.