算法设计与架构设计

清醒疯子 发布于 2015年08月22日 | 更新于 2015年08月23日
tinyfool 尼克徐 等2人欣赏。

最难的是开始,最惨烈的战争是事后。

朋友晓月曾经告诉我,开发三条路:算法、设计、系统。

系统,这条路,需要对文档和环境有足够兴趣,这块不适合我。算法和设计,我倒是很有兴趣。我希望能把算法和设计该怎么做好好想清楚。

算法

对算法有兴趣的朋友可以看这本书:http://item.jd.com/11098789.html

算法,由难到易,有四件事可以做:

1、扩展现有算法的应用领域。

算法发展到今天,已经积累了相当多的存量。除了新创算法以外,目前最迫切的需求大概是需要一大批去研究现有算法,把这些算法的优点扩展到更多领域,优化那些一直被错误操作的地方。这座算法金矿,有两种生意可以做,一个创出有生产力的算法,一个帮更多人进来挖矿。

2、优化算法的空间。

对存储的读写,一直是计算过程最大的限制。如果可以优化算法的空间占用,更少的读写次数,在更小的读写空间上遍历,将有助于提升算法的速度。空间上的优化,造就时间上的同时优化。

3、优化算法的时间。

CPU/GPU等计算资源的提升,使得时间上的优化越来越没那么重要。但如果是从指数级优化成线性级,不管计算资源怎么改变,都会有明显的差别。随着大数据云的扩张,时间上的优化也会得到更多的重视。

4、理清算法的验证方法。

一个算法能不能用在当前环境,在未来一段应用时间,是否可以满足需求,这是对算法认识的最低要求。

架构

对架构有兴趣的朋友可以看这本书:http://item.jd.com/10057319.html

设计,由难到易,有四件事可以做:

1、测试架构的稳定性、可维护性、可扩展性。

一个架构设计到最后,应该有一份详细的比较数据。清楚地显示在什么地方有提升,提升程度如何。这是架构选择的根据,而不是去靠跟别人讨论、八卦、打嘴仗。

2、叠加现有模块满足需求。

通过已有的基础模块和业务模块的叠加快速搭建需求变化所要求的服务。

3、理清模块间的依赖。

通过模块间依赖最小化的设计,将有助于提高模块的独立性,提高模块的复用程度。

4、清楚问题的充要条件。

什么是业务必需的,有哪些地方可以裁减,尽可能降低业务使用的难度,这是架构设计的基本要求。

算法设计上,我一片空白,只读了《算法》第4版200页的书。架构设计上,我非常新手,只初步熟悉VIPER、MVVM、MVCS、MVC,只看了《设计模式》的150页。这是我的算法设计和架构设计框架的第一版,希望在这方面有经验有想法的朋友可以不吝赐教,帮我完善好应该怎么去做这两块工作的框架,不胜感激。

后记(下面以聊家常为主,没时间没兴趣的朋友请直接忽略):

我还在尝试验证“递减原则”。只做了150个仰卧起坐,比昨天还少3个,比前天少150个。健身是非常好的可以反思“递减原则”。以目前的结果看,“递减原则”效果远远差于“递增原则”。

也不是毫无收获,今天第一组做了100个,比昨天第一组的75个有明显提升,比前天的50个更是差天差地。今天,同事都被我能做100个惊到了。

递增原则在总量上也许有优势。但它没有附加效果,更多是纯拼力量。而递减原则往往会有很多附加效果,在总量不足的情况,可以附外获得很多成果。而且,在递减原则下怎么增加总量,我也有一点点灵感。

就是,不要因为下手点的困难辛苦放弃再次尝试,哪怕下次尝试的效果微乎其微。我第一组做了100个,第二组做了10个。这个时候,我觉得今天完蛋了,大概只能110收场了。过了一会,我再做,第三组却神奇地能做30个。

在递减原则,也许,开始的那组会比较困难,但是第一组的困难尝试,却往往可以给后面的尝试打开新的道路。

又比如我对VIPER的尝试,对Casa大大的离散型网格模块的尝试,对Casa大大的数据调整器的尝试,虽然最后未必能直接用到项目中,但见过好东西之后,我就本能地知道比之前好一点的代码应该怎么写。

我用“递减原则”重新优化了一遍我的方法论:疯子一般深入系统。

长久以来,我一直对这套系统非常不满意。因为它虽然从低到高给我在人生选择上提供一个顺畅的指导。但总是让我感到无聊。而且它对高手、老手、新手的指导无法达到同样的效果。

引入”递减原则“,可以让这套方法论有更普遍的适用范围,也就是我现在的算法设计框架的第一点:扩大适用范围。

递减原则,可以让我第一眼就关注到最能让我兴奋的选择。如果我能力不足,才是第二选择,这样可以让我的热情利用最大化,把我的潜力用到尽。

共6条回复
清醒疯子 回复于 2015年08月22日

@xiaotie

希望小铁叔能上来给解解惑,我想知道,算法工作里,最高级那批人在干什么活,第二梯队那批人在干什么活,第三梯队的那批人在干什么活。我想知道活法工作里,不同层面上做的是什么样的事:)

另外,建议大家看看@xiaotie 兄的这帖子,讲的是怎么学图像处理,巨赞:) http://ourcoders.com/thread/show/5786/

xiaotie 回复于 2015年08月22日

1楼 @清醒疯子

汗,大不了你几岁 。。。。。。

既然被点名了,那就多写一点。其实算法的核心是解决问题,而非算法本身。算法是为了解决问题而存在的。

先鸟瞰一下“算法”这东西,程序员眼中的算法更多的是“算法导论”里的算法,这是非常狭隘的算法定义。计算机计算能力还是比较有限的,因此大量的算法是处理离散数据场景,即使是非数据,人们也往往将它转化为比较离散的数据,让计算机来处理。现在计算机的计算能力越来越强大了,随着移动互联网的到来,计算机需要处理越来越多的自然场景(语音,视频,图像等等),所以,通常意义下的算法的重要性会越来越低,而广义的算法的重要性会越来越高。所以我不是很主张深究《算法导论》这样的大部头,里面的知识翻一翻知道就行了,知道他们会让你的代码写的更好一点,但对你解决问题的帮助并不会有多大。

真正帮你解决问题的在于你对这个世界的理解,在于对“边界条件”的分析和洞察。如果你继续看张五常,会发现他对“边界条件”非常的执着。任何理论,需要在一定的前提下才成立,这个前提就是边界条件。算法都是比较简单的,问题的难点就在于对边界条件的掌握。

在我看来,你这1,2,3,4中,只有 3 比较有意义。先说 1,扩展算法的应用领域其实并不是多难的事情,我读大学那时有个发论文的狂魔,用仪器分析的方法分析了一大堆新物质,每个新物质发一个论文,一年发了上百篇SCI,搞材料的要合成一个世界上没有的新物质简直太容易了,然而这些新物质并没什么用途。2,优化算法的空间,这个用途也不是多大,现在内存都大的出奇,因此需要优化空间复杂性的地方并不多。这玩意,可能面试、考试什么的经常碰到,但要知道,那些古老的面试题的出题年代,内存是很贵很稀缺的。3,优化算法的时间。这是当前算法优化很多需要做的地方。越来越多的自然场景需要处理,对计算机的计算能力的要求其高。现在算法优化里,大部分策略都是以空间换时间的。至于4 算法的验证方法,作为程序员,可以不用去关心。这里面,只有3 是重要的。

要我来排序,那么第一档事,应该是解决未解决的问题。这世界有大量未有效解决的有趣的问题,其中很多问题要解决好需要依靠算法。比如说,(我在研究的)翻译电视剧或者翻译公开课时,切轴是个非常烦人的事情,一小时的视频,切时间轴大概要花一个多小时,怎么用程序尽可能准确的把它切出来?怎样将现在的语音合成进一步优化,作出非常萌非常卡哇伊的让人听了就起鸡皮疙瘩让配音演员失业的应用(现在的语音合成还差好远)?再比如,我想做个带智能功能的Sketch,云端有一个模版库,在前端画了一个带颜色的形状,怎么根据这个形状来查询及排序?好吧,再说个非常重量级的问题,这个问题解决好了能够产生一个上市公司出来:html5里有webrtc,webrtc是一套p2p机制,利用它可以搭一套巨牛逼的CDN出来,现在小米和迅雷合作,利用路由器在搞这个事情,而WEBRTC一个页面,就可以当一个路由器用。这些问题都是非常有商业价值的。再以自然场景下的文字识别来说,这个需求在PC时代没啥应用场景,在移动时代就不同了。

处理这些问题,没啥可参考的,即使有可参考的,也是对错各一半。我做过的一个需求是通过不同时间两帧图像的对比,来判断摄像头有没有被动过,查遍了论文没找到类似的。

截至目前为止,我做的这种类型的工作不多,并且也都是初级阶段。但我最终会挑战这一块的,也许还要过两三年,才会正式亮剑,剑试天下。

第二档事是优化、移植解决方案。优化和移植是两类事情。“优化”的应用场景很多。其一,现在大多数解决方案都是凑合赶时间赶出来的,里面有非常多的优化空间,那些关键环节以及可重复性环节都是算法优化可以发挥作用的地方。其二,优化算法可以降低成本,降低对硬件的消耗,或者在同等情况下,让应用更流畅,或者是优化流量、空间占用等其他参数。移植也是很重要的事情,比如说,将纯硬件算法用软件实现,将C++写的算法用JS实现,将PC上的算法移植到移动平台上,等等。

其实我这几年,做的最主要的工作是这个层面的。通常算法的工作平台是C++/Python,我将它变成了 C# unsafe,我使用过的重要的算法,几乎全部都用C#里的 unsafe 手写了一遍。为什么要这样干呢?因为要用它来解决3个问题:(a)开发速度问题。C++开发速度太慢了,Python运行速度太慢了。一个算法开发中,要尝试很多种方案,最终选择一种方案,需要极快的开发速度。通常谈一个算法单子,需要有演示,而演示写出来了,通常工作就结束了。我需要最短的时间,拿出可给客户看的演示。客户有一个需求,你一天都把demo搞出来了,而他第三天还没弄出来,你说这单子谁能拿下来?而在运行速度上,C#写的算法的性能,我做到了C的75%;(b)爽的问题,工作一定要让自己爽,我不认为写C/C++是很爽的事情;(c)学习的问题,我学习一个算法就是把它手写出来,只有手写,你才能了解它的边界条件,了解它的那些量可变,哪些可以调整,用第三方库很难掌握算法的精髓。

第三档事是改变算法的边界条件。几乎所有的库里的算法都是“通用”目的的算法,它往往并不是你所在场景的最好的解决方案。如果你对业务了解比较深,能够通过对现有算法的增加和裁剪得到更优秀的算法。能做到这一点,算“研究员“或“自身程序员”了。

第四档事是有意识的去使用现有的数据结构和算法。选择什么样的容器类型及使用什么样的缓存方案是平常写代码最常用的两种场景。再比如,怎么快速判断两个视频文件是同一个文件?再比如,数据库的索引类型,搜索中的倒排索引;多维检索里的KD树等等。一个操作,采用A方案和采用B方案,粗略估计它们的速度区别。高级程序员大概能达到这个层面。通常学数据结构和算法,应用到此为止。

这里没提新算法的发明,那是数学家的事情。

再回到前面的话题,学好算法,有助于解决上面2-4类事情,对最有价值的第一类事情帮助不大。

第一类是价值之源,赚钱的根本。虽然我现在是靠第二类来赚钱的,但已经到瓶颈了,最终要靠第一类来突破。

同样是做算法的,很多人做不下去,做不出收入,而我这么一个半路出家的做的挺好的。为什么呢?不在于掌握算法的多少,不在于算法基础的好坏,而在于对问题自身的了解,对业务领域的了解。

让我们放弃书本上对算法的定义,换一个更新的定义:算法是对工程问题的形式化解决方案。

一个问题只有形式化之后,才有可能由程序来解决。

如何形式化问题,是最本质的挑战。比如说,判断摄像头动没动,那么什么叫动?判断图像模糊不模糊,什么叫模糊?判断图像偏色不偏色,什么叫偏色?很多问题,只要合理的形式化,就解决了一大半了。而如何形式化,要靠天分和洞察力。

在这个领域要做出成就,数学很重要,天赋非常重要。在我这个穷乡僻壤里,没有资金,没有人才,其他的都玩不转,我只能玩这个啊。天赋俺不缺,所以在补数学。

不知道最高层的那群人在干啥,俺独来独往,跟人没交流。

我只知道我很爽。怎么比喻呢?如果说写产品是写小说,那么写算法就是写诗。五杀超神的爽快是写别的程序很难体会到的。那种秒杀的快感,与未知搏斗的惊心动魄,非常的写意。要不没进展,要不直接秒杀。

一个客户提出的业界新出现的需求,脑子灵光一闪,啊明白了,一会就搞定,然后赚了几万块钱,这种心情能否体会?

当客户盛情邀请你去公司,说某个问题他们解决了两个月没解决好,你的方案要好得多,比市面上的几款产品要好,而这是坐在咖啡桌边一会就敲出来的,这种成就感能否体会?

当客户拿着嵌入你的算法的APP,在外面大吹特吹业界第一个做成这样的,还tmd没人反驳,融资上千万,这种心情能否体会?

当一个行业内共性需求,想了一个形式化方案,然后写代码验证下,写完一看,我靠这问题不会这么容易就他妈的解决了吧,这种傲娇能否体会?

算法是程序员的浪漫。

尼克徐 回复于 2015年08月22日

2楼 @xiaotie N多干货啊,谢谢分享!

喜欢那一句:“算法是对工程问题的形式化解决方案”。

也谢谢@清醒疯子 的好问题。

清醒疯子 回复于 2015年08月23日

2楼 @xiaotie

谢谢小铁兄:)

这次算是对算法对一个最基本的认识,还想问3个问题:

1、算法从PC到移动,是只需要换个语言写一遍吗?还是有很多其它的事情要做呢?

2、一个算法卡壳很久,是继续一直强攻呢?还是告诉客户一时半会解决不了,放一放呢?

3、业界算法论文,是接单后再去看呢?还是平时就每天抽点时间看?

xiaotie 回复于 2015年08月23日

4楼 @清醒疯子

1,我写算法的流程是,用C#把算法写出来,然后在windows和server端使用,如果需要Web端或手机端,再用C++重写一遍。核心算法是C#或C++写的,demo是各个平台自己的语言。

2,放一放

3,以前看看,现在很少看了。目前很少接单,兴趣来了做一做。只做自己规划内的。

梦中醒不过来 回复于 2015年08月23日

我觉得方法论一旦去到细节,每个人都会不一样,不必苛求普适。

登录 或者 注册