V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  noli  ›  全部回复第 36 页 / 共 45 页
回复总数  897
1 ... 28  29  30  31  32  33  34  35  36  37 ... 45  
2016-03-05 23:10:40 +08:00
回复了 WIwindson 创建的主题 程序员 RESTAPI 实际应用的一些疑惑。
@Wlwindson

主流是根本不防注册。有多少个 email 地址可以拿来注册?多多益善。
起码给投资人的数据好看。

不过看来你也没打算按主流做啊?不然这根本就不是问题
2016-03-05 13:49:45 +08:00
回复了 WIwindson 创建的主题 程序员 RESTAPI 实际应用的一些疑惑。
应该说,用了 RESTAPI 使得你列出来的这些问题更好解决了。

1. 如果你的 RESTful 框架支持 filter 或者类似的东西,你可以针对 get 方法来做限制;相反如果你不是用 restful 的话,鬼知道你要针对怎样的 url 和请求来做限制?

2. 针对恶意大量注册,新加一个验证码 AP ,用来给填对了验证码的注册用户发 token ;然后实现注册逻辑的地方,从数据库里面校验这个 token ,就解决了。 如果不用 restful ,很可能你就要把 注册和反机器人写在一个逻辑了。
2016-03-04 22:22:04 +08:00
回复了 jsq2627 创建的主题 .NET 有没有朋友在使用 LLBLGen?来评价一下吧
@jsq2627 如果是写通用缓存(跨语言跨组件通用)的话,那么 ORM 这个东西就很难写,毕竟你不知道要适应哪些语言,怎么把语言模型映射为自己的模型。目前为止我见过的 ORM 都是针对单一语言的。

如果是语言专有的缓存,例如 C#,显然自己动手丰衣足食啊。
我也曾经用 gevent 写过 Python 专用的缓存,写一个单线程的应该很容易吧?
2016-03-04 22:11:04 +08:00
回复了 jsq2627 创建的主题 .NET 有没有朋友在使用 LLBLGen?来评价一下吧
查询结果缓存这些,应该不可能有 ORM 替你完成的吧?
如果需要查询缓存,可能需要额外部署一个 Redis 或者别的缓存。
@skydiver 我错了,确实是 inotify 。 你说的是我想说的那个东西的正确名字。


nodejs 封装了 inotify
@skydiver 自己稍微 baidu 或者 google 一下又不会怀孕……非要浪费我 5 个铜币

https://zh.wikipedia.org/zh/Inode

inode 是指在许多“类 Unix 文件系统”中的一种数据结构。每个 inode 保存了文件系统中的一个文件系统对象(包括文件、目录、设备文件、 socket 、管道, 等等)的元信息数据,但不包括数据内容或者文件名[1]。
你只需要知道 linux 有 inode ,用 libuv 或者 nodejs 干这个应该简单得不能再简单了
2016-02-28 02:03:13 +08:00
回复了 eightqueen 创建的主题 程序员 整理了一下 IO 多路复用的学习笔记
用 Python 代码来描述 IO 多路复用原理,是不是有点不合适啊?
Python 太高级了吧
@iheshix 用户不主动把数据交给对方,而是服务者请求获取数据。但是这个设想跟现在的生态恰好是反过来的……主要是很多人也都没有意识到自己个人信息的价值(然而很多人的个人信息可以质变成很有价值的东西)。

说实话,这个不是技术问题,而是经济和政治问题。我不觉得是技术就能解决的。
隐私条约是迟早要有的,但现在不能指望。
不能指望法律啊媒体啊什么的,因为没有代表用户的根本利益。

用户应该自己组织一个消费者权益团体,才能保护自己的利益。
当然,这是要代价的,很大可能就是金钱代价。
2016-02-22 00:23:15 +08:00
回复了 linkbg 创建的主题 Python 请问为什么要使用 rest api
rest api 代表的是一种正交分解问题的设计思路……
好吧,这句话估计对很多人来说都很费解,估计跟没说差不多……

打个比方,把实现一个软件系统的过程,比作铺瓷砖;不能完全铺满,露出空隙或者边角位置的粗糙地面,类似于有 bug 或者照顾不来的需求。

这样的话,如何设计瓷砖的形状和大小就很有学问了;

一块瓷砖或者小瓷片可以覆盖一定的面积;写一些分代码也可以解决一部分需求。
设计好一个形状大量制造的成本会很低;同样地,按照一定的规范写代码,这部分代码也可以很广泛地运用,成本也可以降得很低;

但是如果你用圆形或者星星形的瓷砖,虽然单个看起来很漂亮,但那几乎意味者地面很难完全覆盖;

铺瓷砖是一个平面几何问题;

可是设计 api 是一个非欧几何平面上的平铺问题,
rest api 是设计一个好的形状的一种尝试吧。
2016-02-15 10:49:59 +08:00
回复了 tabris17 创建的主题 MongoDB 两阶段提交遇到无法恢复也无法回滚的事务该怎么办?
“ A 向 B 转账”(记为 T1 )的事务完成或者中止之前能够修改 A 帐户余额?
我不确定 T1 还能不能叫事务……
2016-02-15 00:26:39 +08:00
回复了 zxgngl 创建的主题 程序员 我看自动驾驶技术 by Yin Yang
幸存者偏差…… 作者应该再考虑一下有多少人考不到车牌或者一上马路就出事……
2016-02-04 15:56:11 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@cloudzhou

switch case 和 exception 的作用肯定不一样啊。

1. 如果 SocketException 的各种 ErrorCode 都以 SocketException 的子类出现,要么我用 SocketException 一个 catch 把各种子类全部捕获了,在这种情况下,你才需要根据子类细分再手动 switch case 来处理 —— 这时候很有可能会漏掉某种子类,这个弊病跟用返回值处理是一样的

2. 然而你也可以 catch 每一个 SocketException 的子类,这样就是编译器替你做了 switch case
这种情况下你一样可以针对细分情况分别做处理:

再然后
2.1 如果我的疏漏了 SocketException 的子类没有捕捉,并且也没有 catch SocketException 的本尊,那么,会 crash

2.2 如果我最后有捕捉 SocketException 本尊,甚至直接 catch Exception (所有 Exception 的共同父类),那么尽管我依然遗漏了情况没有处理,但是因为 catch 了, exception 发生后的代码就不会被执行了,程序不会 crash 并且后续的代码不会意外地使用了无效的返回值。

也就是说,像 golang 里面这样的错误, 也是 @goool 代码里面的问题:

func send_data(n int, target string, content string, result chan Pair) {
conn, err := net.DialTimeout("tcp", target, time.Duration(1 * time.Second))
if err != nil {
result <- Pair{n, err}
return
}
defer conn.Close()

DialTimeout 的作者不必在异常发生时硬要给 conn 塞一个值,
而调用 DialTimeout 的时候也不必防御性地 return
要一遍又一遍地重复写这些 resut <-Pair{n, err} return 这种代码,我真的不能认为它 DRY

再况且,我本来出这个题目,就是要考验 golang 处理错误的能力。
他的代码根本就无视了这一部分的逻辑,你看起来当然简洁易懂咯。
实际上,就以这段为例,至少要检查一下 err 的具体情况,才能决定 Pair 是不是应该送出去。
这时候你就会发现谁的代码里面到处都是 switch case 了


再看看 抛异常的方案, send_x_target 的主要逻辑 就这几行:

var client = new TcpClient();
await client.ConnectAsync(endpoint.Address, endpoint.Port);

var stream = client.GetStream();
await stream.WriteAsync(content, 0, content.Length);

var reply = new byte[1024];
var respLength = await stream.ReadAsync(reply, 0, reply.Length);

两个版本里面都没有变过

你觉得“ Golang 显然容易理解多了”
我只能说你的口味和我的太不一样了
2016-02-04 14:48:52 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@cloudzhou 你说的这一点就是我为什么特意用 C# 的 SocketException 来做对比的地方了。

事实上, SocketException 就应该为每一个不同的 ErrorCode 独立写成一个 SocketException 的子类。这样根本就没有什么 switch case 的需要,编译器帮你做了。 C# 这么做纯粹是历史遗留问题。

而没有 exception 就必须总是用类似与 switch case 这样的分支结构来处理这些错误,也就是我说的为什么容易导致疏漏的原因。

再况且,只要它是一个 exception ,不 catch 程序就要死掉。不会让错误扩散, golang 呢?骗过了编译器以后,运行时的错误结果还是会扩散出去的。

你非要说 exception 改变程序流程,那是因为 Java Exception 的脑残设计,滥用 Exception 把它当作类似于 yield 这样的东西来用。
难道 golang 的 defer 就不会被滥用了? 到时候情况会比 Java 好很多吗?
2016-02-04 14:36:59 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@goool

“ try/catch 强迫程序处理错误,而返回值没有强迫,所以返回值不好”
这不是我的观点。

我的观点是, golang 通过多值返回 err 很容易导致 “推卸责任的行为难以收拾”,所以 golang 通过多值返回处理 err 是个逗逼的设计。 而不是“返回值不好”。


“ golang 的 defer 会改变代码的执行流程”
这个也不是我的观点。

我的观点是: defer 会使得看代码的顺序和代码执行的顺序不一致,十分烧脑。
不信请自己看 https://tour.golang.org/flowcontrol/12

package main

import "fmt"

func main() {
defer fmt.Println("world")
defer fmt.Println("Awesome")
defer fmt.Println("Golang suck")

fmt.Println("hello")
}

试试猜猜输出顺序是什么?
如果再嵌套多几个别的资源,你觉得这不是一个更加反人类的设计吗?

另外多说一句 defer 会使重要资源的释放不必要的推迟(必定是到最后才回收),又是一个脑残设计
2016-02-04 14:13:32 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@goool

那个 shouldStopTrying 其实目的很简单,就是不停地重试。最后应该加个 finally 判断一下什么时候不需要再重试了,但是我没有加,这要看需求,但是不影响 SendContentToTarget 。由于在 C# 里面 class 类型( HashSet 是一个 class )的参数传递都是 by reference 的,所以可以通过多次调用同一个方法,来不断地移除 HashSet 里面的元素。

我先说说我对你的代码的理解:

你的 send_data 目标应该是类似于我代码里面 29-53 行的 try block 里面做的事情。
然后,你的 main 函数里面做的,目标应该是我的代码里面 SendContentToTargets 做的事情。
你用一个 channel 来把“发不过去”的地址传出来。

然后,我俩的代码都回避了返回值的设计,我感觉我俩都没到点上。

如果对你的代码没有理解错的话,我认为有以下几点造成我和你的代码的实际功用是不一致的:

1.
发消息或者等回复的失败,并不应该视作“地址发不过去”,而是应该重试。
所以在我的代码里第 66 行会把这个事情扔给 SendContentToTargets 的调用者来处理,譬如说如果重试次数超过了多少,就不试了,认为它不发送不过去。 shouldStopTrying 就是为这个用的。

2.
如果目标地址的列表太长了,导致打开文件数量太多,那么运行到一定程度之后,我的代码会在第 31 行或者 32 行抛出异常,但无论是在 54 行接还是 92 或者 96 行 catch ,都不会导致判断 “该地址发不过去”。

但是在你的代码的第 12 行 看起来并不会做这个区分(连接超时还是打开文件数到达上限),并且我很好奇,如果其实根本没有连接上,那么 defer 的时候又手动 Close 了一下,是不是里面会自动判断有没有真的连接上? C# 的 try catch 机制在这个 socket Dispose 的时候会做合适的处理,然而 golang 里面虽然有 GC ,但是这资源的释放跟 GC 似乎是两回事,不知道 golang 会怎么处理?

如果是自定义的对象而不是 golang 标准库的对象呢?
当然,以上的这些你都可以认为是无关重要的细节……然而,正是这些细节会影响你的代码的可重用性和健壮性。



其实我希望看到的是,用 golang 做这个事情的时候,是不是能够把不是 send_x_target 该管的东西放在 send_x_target 之外的代码来处理。

譬如,在 ** 不更改 send_x_target 的签名前提 ** 下,我可以这么改:

https://segmentfault.com/n/1330000004414242

把控制什么应该重试,什么应该排除的条件指定放在外面,这样, send_x_target 就变得更加纯粹了。
2016-02-04 11:51:27 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
想起 @codeaqua 说 try catch 会破坏正常代码的 flow ,我想想也是笑了,好像 golang  的 defer 不会改变 flow ? python 的 yield 难道也不改变 ?
2016-02-04 11:39:30 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@bombless 我不理解你想说的是什么。“无法预期调用者会抛什么异常” 这个难道是你说的 “破坏了类型检查的原因?

可是异常之所以叫做异常,就是因为它存在  没有被捕获 的可能性,才叫异常的吧?异常没有被捕获就会在抛出点导致 crash ; 而 err 被意外地忽略了,然后继续执行,程序被预期以外的数据影响到别的地方的代码然后导致 crash ,这种情况不是更应该被警惕吗?

“返回错误,和抛出异常,根本就是不一样的结构;既不是顺序也不是分支,而是跳转,而返回错误依然是一个顺序结构之中。”

这句话你可以这么来理解: 在一个 try catch block 中间的代码,你可以认为是用一个独特的 goroutine 来运行的;这个 goroutine 与 try catch block 之外的上下文之间有一个 channel 用来通知异常。所以,当异常发生的时候, try catch block 中间的代码只是被中止了执行并没有自行退栈,而异常被传递了出去;返回 err 则不一样,函数被认为已经完成了随着 return 会退栈。

在局部上,你可以认为,在 try catch block 之间的每一行代码之间,编译器都会自动地加上等价于 golang 的 if err != nil { notify_exception(...) } 这样的代码(事实上 C++ 的编译器就是用类似的原理来实现的,会记住代码帧执行到哪一步) —— 或许这也是某些人认为 返回 err 和 try catch 除了手工增加防御性的代码之外,并没有本质的区别 ,然而 ——

notify_exception 把控制权交给了上层代码,这个上层代码并不仅仅是 try catch block 所在的上下文代码,还包括了调用栈上更靠近栈底的所有函数帧上的代码,就是说,那个用于通知异常的 channel 的 scope 是跨越 多个调用层次的;而没有 exception handling 机制的语言,例如 go 例如 C ,要做到这样的效果,就必须在相关的代码上层层防御——有没有嗅到一阵代码耦合的气味?

用 C 反而会更安全一点,因为 C 只能返回一个值,而调用者 *总*是* 有责任去判断这个返回值是否符合预期,譬如 bsd socket 的 recv 返回类型是 ssize_t , recv 的简单形式是告诉调用者接收了多少个字节(理应是非负数)然而 ssize_t 也说明了它会返回负数值 (异常发生),在这种情况下,其实就是一个弱化版的 checked exception 也就是非常接近 Java 的那种做法的本质——你*应该* 在调用的现场就处理好所有的异常,所以层层防御并没有在 C 里面成为现实,但即使是这样, C 代码依然非常容易耦合抽象程度很低。而 Java 的 checked exception 得益于其标准库的完备性,在编译的时候就已经强制保证了所有 exception 都要正确地被 catch 。 C 还是要看程序员个人修养。

然而 golang 用多值返回来描述异常,就打破了这种类似于 checked exception 隐含的强制性。多了一个 err 返回出来,就意味着懒惰的程序员总是有办法把责任往上扔,并且不怎么影响函数的返回值的设计,因为可以多值返回嘛——这跟懒惰的程序员总是接住所有的 exception 又不处理简直是一样的;

你甚至可以自己去看看 golang 自己的官方例子,产生了一个 err 之后,有什么东西可以阻止偷懒程序员或者做得昏头昏脑的程序员,继续去使用无意义的返回值去做任何事情吗?难道把 err print 出来事情就完了吗?

更坏的是,经过多层往上推卸责任之后,上层代码已经无法知道 扔上来的 err 到底是个什么鬼了——越是靠近调用栈栈底的函数,这个麻烦就越大,因为调用链越长,可能调用到的其他函数的范围越大。这个时候你必须猜这个 err 的所有可能性,想小心翼翼地处理这个 err 只能看运气,遗漏了处理某些具体类型的 err 的风险总是存在。
从这个角度来说, C++ 可以 throw 任何东西上去实际上也不是什么好的设计,尽管 C++ 还可以用 catch(...) 的语法来保证接住抛上来的任何东西,在需要阻止异常扩散的时候还有最后一招。

如果使用类似 C# python 等等的这种异常机制,首先是解除了处理 err 的耦合,并且总是保证,如果异常没有被恰当的接住就立即 crash , crash 的时候还可以保留现场,告诉 debug 的人是哪里导致的 crash ( golang 是做不到的,想好好地 log error 只能靠所有人都自觉),实际上这样才能更严格的要求调用者考虑清楚异常的类型;如果写的时候没有考虑清楚,那么跑的时候总是会的。

就算懒人程序员用类似于 catch(...) 这样的方式来偷懒绕过所有的检查和避免 crash ,它也没有办法把错误数据的影响扩散到其他地方,不会危害到其他地方的代码安全性。

综上所述, golang 的多值返回 err 的设计,就是事情没干得更好,倒是更容易让人做出更坏的事情出来——简直就是开历史的倒车。
2016-02-03 18:53:08 +08:00
回复了 fire5 创建的主题 Python 看了一个 go 语言,感觉语法略为不习惯。
@goool

我预计 go 的做法会一点都不 KISS
我期待你可以给我一点惊喜。
1 ... 28  29  30  31  32  33  34  35  36  37 ... 45  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   963 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 29ms · UTC 21:28 · PVG 05:28 · LAX 14:28 · JFK 17:28
Developed with CodeLauncher
♥ Do have faith in what you're doing.