Oladipo Planet

无知和弱小不是生存的障碍,傲慢才是

从“一首歌”到一首歌的距离

很久很久以前,有个小哥一直想当个民谣歌手。也许是受了李志、赵雷、许巍等人的影响。可是为什么不想成为摇滚歌手呢?因为要摇滚一个人搞不了呀,吉他之外贝斯、架子鼓都是必不可少的。想更丰富一点,再配个键盘手,再民族一点加个笛子和三弦,最后这就成了何勇的那首《钟鼓楼》了。

可是光靠想也成不了民谣歌手,于是他买了乐理书和键盘。断断续续不知道过了几个月,以为乐理已是心中有数,键盘能弹些小曲便已入门。嘟囔着民谣歌手已经这么久了,是不是可以试着写一首歌呢?于是又自不量力地写起了歌词。刚巧他看完了《三体》觉得民谣应该取之于生活,写一首《三体之歌》成了顺理成章的事情。他最后也承认这歌名确实有点Low,只是对于一个整体都很Low的东西,没必要以标题党博眼球,所以就心安理得不少。

三体之歌

一个星球 两个星球

一个一个不为人知的时空

一个文明 两个文明

一个一个存在又消去

一株鲜花 一片绿地

暗夜还待黎明 还有风和雨

一块墓碑 一段残壁

关于过去 仅剩下只言片语

你在你的世界里光阴似箭

而我在我的世界停滞不前

时间它割裂了我们倆

我正青春而你已入暮年

时光啊一去它不复返

远走的人他不能再相见

时光一去啊它不复返

远走的人他不能再见

歌词还是浅显易懂的有木有。其实一开始只是哼出了最后一句,自以为还蛮有副歌的样子,才顺势把词写完全。《三天学会写歌》里面也是这么个思路。这本书先讲了基本的乐理,然后教你如何从一个灵感开始,定调、定节奏、定和弦,最后填词成为完整的一首歌。对于创作流程能有个完整的认知,技术细节什么的真的是不可能一蹴而就的。对于《XX天精通XX》系列丛书还是要保持清醒认识的。

对着写完的歌词哼唱了一遍,感觉也像那么回是。结果卡在了下一步——定调。因为没有相关的视唱的练习和经验,导致完全不知道唱在什么调上。有些音能通过琴键找到,有些则完全找不到那个音,不是过高就是过低。尝试着用软件分析,但效果并不好。但它们在其它方面帮了不少忙,还是非常感谢他们的。

apps

因为确定不了每个音的调,所以就无法给这首歌定一个基调,也无法给每个小节添加和弦,也就没有后续的步骤。写歌的第一次尝试到这一步也就戛然而止。从“一首歌”到一首歌真不是去掉引号那么简单的事情,实不该那么急于求成。明明才刚入门依旧有许多要练习的东西,在器乐上还需要强化节拍,增加左右手同时的训练,在不同调式上的演奏和伴奏。而且需要启动视唱方面的练习。写到这里,发现在音乐乃至其它领域的学习同编程一样,需要把一个大工程拆分许多小项目,各个击破获取成就感才能保持前行的动力。在这个过程中需要不断地Practicing and Hacking。

一句话描述iOS中的设计模式

本文是对《iOS Design Patterns》中涉及到的设计模式的简要概括。

虽然设计模式种类繁多,但是总体上又可以分为三类

Creational侧重于类实现的功能。Structural侧重于对象之间的组合结构。Behavioral则是提供了对象之间的一种交互方式。

观展记I

上周末在上海当代艺术博物馆观看一口气观赏了三个不同主题的展览,分别为坂本一成和大同大张的个展和意在尝试新的展览机制汇集了很多作品的的青策计划。对于一个外行人来说,设计上面的认知非常有限,斗胆在局限的认知中评述一下个人的看法。希望能藉书写文字逐渐拓宽在各领域的认知。

反高潮的诗学 坂本一成的建筑

以住宅设计实践出发来思考建筑的可能性已成为日本当代建筑探索的重要途径,个体性住宅所积聚的建筑魅力正受到越来越广泛的关注。坂本一成通过住宅设计来思考什么是建筑,什么是人与建筑的关系。从“箱体”、“家形(型)”、“架构与覆盖”到“小型集合单元与岛状规划”,在坂本的建筑中,我们发现结构中“形”正在褪去,更为抽象的“型”正释放出柔软而透明表情。建筑师以缜密的个人思考与个人化的形式保持距离,将煞费苦心的推敲藏于宛若自然的形式之中,站在“刻意”的反面,让概念幸免于形式的俘获,让形式收获真正的自由。而那些具象的建筑“原型”——那些对于建筑来说不可或缺的尺度、场地、材质、结构、覆盖,则被视为“避免陷入另一种抽象极端的武器”。

于是,概念和现实之间随时可能崩离的紧张对峙,使坂本一成的建筑获得了抽象和具象相叠的两义性。在他看来,禁锢住高潮的手段犹如走钢丝般惊险、谨慎。积蓄着能量的高潮尽管令人向往,但在它迸发的同时也意味着结束、死亡、封闭,以及一切负能量的降临。如果把高潮视为完成时的话,那么,通往高潮的进行时恰是那置身愉悦的源泉。

1552 粗看房屋平淡无奇,造型规整甚至可以用简陋形容,墙面颜色偏银灰色并不是房屋的常用颜色,会给人有一种生硬冰冷的感觉。关于这幅画的有一段文字描述:

外墙采用有凹凸感的清水混凝土材质,形成所谓的“未完成”状态,以银色漆面涂刷。既是虚构,同时也是实存的;既是象征,同时也是物质的。作为坂本初期代表作,两义性的特征在其间被重叠交织。

认知了作者的创作意图后,再回看这幢房屋,就不再只关注感官上的体悟,而是时不时跳出眼前的场景,呆呆地想着二义性。最后它就成了我最喜欢的房子之一。

1546

日本是个自然灾害多发的国家,房屋普遍矮小,空间有限。然而坂本在设计上还是非常舍得牺牲空间。有时为了房间之间能够有层次,会刻意或者因势利导去创造一些落差。刻意的落差是以垫高某些一区域为代价,垫高的部分没有被利用起来容易造成空间浪费。写到这里的时候我抬头看了下天花板,发现头顶的区域其实一直是空荡荡的,那么是否可以理解坂本的设计只是牺牲了一部分上层空间,达到错落有致的室内环境。在某些公共区域包括个别住宅(没记错的话)会有上下贯通大厅,这一部分的上层空间的的确确是被浪费的。

当然坂本也有空间利用很好的案例。比如设计的一幢两层房屋,却可以同时容纳10户租客。因为划分了不同的入口,使得体验上并不拥挤。

Mantle源码阅读笔记

Mantle是一个为CocoaCocoa Touch的Model层提供JSONObject之间转换的框架,因其提供了较其它框架更为丰富的功能而被广泛应用。下面逐一谈下主要特性的实现原理及我的收获。

相同属性名的映射

Mantle通过MTLModel协议规定了一个可转换对象应当具有的行为,并在MTLModel类中给出了实现。MTLModel类虽然给出了协议的所有实现,但是本身并没有用到。只是通过KVC的方式提供了NSDictionaryModel的映射,但是处理得非常谨慎,考虑到了内存泄露的问题,可以参考以下代码。


static BOOL MTLValidateAndSetValue(id obj, NSString *key, id value, BOOL forceUpdate, NSError **error) {
	// Mark this as being autoreleased, because validateValue may return
	// a new object to be stored in this variable (and we don't want ARC to
	// double-free or leak the old or new values).
	__autoreleasing id validatedValue = value;

	@try {
		if (![obj validateValue:&validatedValue forKey:key error:error]) return NO;
		if (forceUpdate || value != validatedValue) {
			[obj setValue:validatedValue forKey:key];
		}
		return YES;
	} @catch (NSException *ex) {
		NSLog(@"*** Caught exception setting key \"%@\" : %@", key, ex);
		// Fail fast in Debug builds.
		#if DEBUG
		@throw ex;
		#else
		if (error != NULL) {
			*error = [NSError mtl_modelErrorWithException:ex];
		}
		return NO;
		#endif
	}
}

MTLJSONSerializing协议继承了MTLModel协议并加入了三个重要的拓展,大大增加了灵活性。

APIBlueprint To Swift Request

这是一个个人项目,目标是将描述Web请求的文档自动转换成用Swift实现的网络请求。前面一部分功能已由APIBluePrint完成,我编写的模块复杂将Json格式的文档描述文件转换成Swift代码。

API Blueprint语言

API Blueprint is simple and accessible to everybody involved in the API lifecycle. Its syntax is concise yet expressive. With API Blueprint you can quickly design and prototype APIs to be created or document and test already deployed mission-critical APIs.

Drafter

将API Blueprint的文档解析成JSON或YAML文件。AST的格式已经启用,以Refract Parse Result为主。

drafter -t refract -f json blueprint.apib

Drakov

Drakov是一个Mock Server,解析API描述文档为测试提供伪数据服务。

drakov —f blueprint.apib

Swift大会填坑之旅

• Swift

中国第一届Swift大会已于2016年1月10日于北京结束。会上内容非常全面有价值,在Github有资料分享,会议视频在慕课网上可以看到。没有现场参与会议还是深表遗憾。此篇文章作为阅读讲义后的初步总结,如有疏漏还望指正。

Think Functionally

Functor,ApplicativeMonad是函数式编程的三个重要概念。ReactiveCocoa就是这三个概念的实践。Functor,ApplicativeMonad是分别实现了接口(typeclas)的数据类型,并依次包含。最终使函数和数据可以通过统一的接口,处于一种平等的地位,无缝灵活地组合调用。这也是通向声明式编程的一种途径。帮助理解这三个概念的文章推荐雷纯峰的《Functor、Applicative 和 Monad》

傅若愚主讲的《Objective-C to Swift》和包涵卿《Functional Programming》中均给出了用函数式思想流式处理异步代码的实践。包涵卿讲稿中涉及到的Promise和Nomad这两个很相似的概念,这两个概念又分别衍生出框架PromiseKitReactiveCocoaPromise倾向于对异步过程进行封装,通过一个队列维持依次执行的顺序。ReactiveCocoa倾向于对数据的封装,以组合和数据流的形式执行方法。

翁阳《Swift改善既有代码的设计》的实现方式粗看和Monad很像,实际上并不涉及数据流的传播,只是通过重载操作符巧妙地“隐藏”了异步操作中的嵌套,代码相互独立。在可读性上确实有了质的提升。

Protocol Struct and Enum

随着Protocol重要性的增加,Swift已经具备纯正的面向接口开发能力。Protocol已经全面支持ClassStrutEnum,可以自由组合并通过extension来拓展行为,相比OC中通过Category添加协议的主要作用是隐藏实现细节。Swift中接口作为一种数据类型可代表一类具有相同行为的对象,可以直接传递和调用,非常方便。

StructEnum的使用频率有非常大的增加,尤其是Struct。在Swift标准库中定义了多大102个结构体而类只有5个。StructEnum已经具备同Class一样的PropertiesMethodsProtocol能力,区别在于结构体和枚举类型不能继承,在参数传递过程中是复制传递,这能避免类对象通过引用传值引起不安全的多线程操作。结构体的效率也比类要高得多。所以在Swift中多推荐首选结构体。

李洁信在主讲的《Pop in Swift》中给出了两个用Protocol解耦代码的例子。其中第二例子,MVVM中ViewModel使用Protocol对View渲染的代码进行解耦,增强了代码的复用性,非常值得借鉴。

Performance

周楷文小哥带来的《Faster App》给出了优化程序性能的方案,讲的比较全面,且不限于Swift语言。性能优化通常都会涉及到后台执行耗时操作缓存复用以及为了效率使用更底层的函数,具体方案根据使用场景而定。

Swift Style And Building a Framework

gregheo小哥讲了一些关于Swift的编码规范,如何让代码清晰可读性强。在他的Github上有很具体的规范可以参考。

猫神的主题是《如何打造一个让人愉快的框架》,讲述了打造第三方框架需要注意的几个方面:

最后猫神推荐了一个持续集成的方案fastlane,自动化部署frameworks。

总结

本来以为只是写个概要,怎奈讲稿的信息量比想象的大得多。光是去理解函数式编程从一个坑跳到另一个坑,而且适时选择不继续跳坑,这才断断续续花了近一周才完成这篇文章。对函数式编程和Swift特性的理解还不全面,需要进一步巩固。现在迫不及待想实践中应用学到的知识了。

参考文献

薄荷App开发中用到的第三方库

这篇文章简述了我们在重构薄荷App时所采用的第三方库,这些库是一款功能完整的App必要的组成部分。 在这里只是简单讲述各个库的应用场景或实现原理,有些比较复杂的框架还请读者自行了解其设计思想和使用方法,恕不累述。

模块化的网页开发思考

这篇文章用以陈述现有购物功能的弊端,同时展望下移动端网页模块化的实践前景。分析场景为商品详情页。文章的思想和我之前一篇《评测框架简述》类同,只不过把平台从iOS移到了Web前端。

商品详情页是由Native和WebView组合而成的页面,Native部分包括上部分的轮播器,商品名称和单价销量。Web部分用以展示商品详情,包装信息以及可以跳转到Native的评价标签。 screenshot1

轮播器出于性能考虑用原生实现是可以理解的。但是食品名称单价两栏并不是Web页面就让人诧异了。因为原生实现并没有体现任何优势,反而不利于实时更新。比如我们今天想来个促销,把28.0划掉,旁边写上9.9,这样的事情原生就办不到了。

这些都不是最重要的。

最重要的是下面的静态页面(上图蓝框部分)是以很低效的纯手工方式编写的HTML代码。它存在以下缺点

  1. 低效
  2. 灵活性差,维护成本高
  3. 专业性强,不懂HTML的业务人员没有能力修改

为了将来有更大的发展空间,我们需要抛弃历史的包袱,重新构建新的实现方式。

数据源和模板分离

恰巧我朋友所在的堆糖公司实现了一套模块化的页面配置系统。就是将网页元素分割成一个个模块,每个模块有独立的数据源和展现方式,模块之间灵活组合,由模板引擎负责在浏览器端拼合和填充。最重要的是最终页面的生成是由不同技术的市场和运营的人完成,大大降低使用门槛,提高效果。

数据+模板—>前端模板引擎渲染—>HTML页面

这和由服务器渲染页面类似,只是把渲染过程移到了前端。这样做的好处有许多

  1. 模块之间独立灵活易组合
  2. 数据源和模板复用
  3. 维护成本低
  4. 服务器减少了渲染过程,性能提升
  5. 省流量,服务器只负责返回必要数据源,模块相关代码存放在客户端本地
  6. 使用门槛低,非技术人员也可以通过组合模块生成页面

下图是在这个体系中各个角色所承担的职责。 screenshot2

What to do next?

在这个系统中,所有的数据源都是人工输入的。可以理解为是一个静态模块化系统。那么动态模块化系统是什么样子的呢?我们可以由市场和运营的人来设置一些约束或查询条件,由服务器根据这些条件计算得出相应的数据源。现阶段我们更需要静态模块化的功能,之后再根据需求来决定是否跟进动态的版本。

关于产品的一点思考

任务系统

Elevate是一款品质极高的学习App,从听说读写各个角度来提高个人的学习能力。Peak则是侧重从游戏中提高人的思维敏捷性。他们有几个典型的特点。

  1. 循序渐进的任务难度,逐渐探知个体的极限。
  2. 任务不多,相互独立。容易利用碎片化时间。
  3. 形式种类多样,适应不同人群。
  4. 有较科学的评级。

个人认为,凡是脱离舒适区的行为,对大部分人来说不会是好玩的事情,比如学习比如减肥。所以,与其说把任务系统做得好玩,不如说做得较容易获得满足感,荣誉感,对未来能有所期待。就好比打游戏,一味的打怪必然是乏味的,之所以要不断去打,就是希望能够在升级之后能够有新的能力,新的套装,新的副本可以尝试。

任务的循序渐近还有一个好处,就是容易养成习惯。就比如拿我用Elevate来说吧,其实每天学英语心里上是有点抵触的,但是好不容易坚持了一段时间,说中断就中断,于情于理都不忍心,所以还是会时不时进行练习。任务系统是一个可以抽离出来独立的系统。需要综合以上几点,并拥有适当的等级制度,奖励措施,营造良好的竞争氛围。需要做的工作还是很多的。

混合开发

  1. 开发效率高
  2. 跨平台代码复用
  3. 验证想法,快速迭代
  4. 易于维护,线上实时修改

案例1:H5开发一个展示丰富的引导页只需要一个小时,然后就可以应用于iOS和安卓平台。而在iOS或安卓上实现此功能花费不止一小时,且重复开发的时间人力成本不止两倍。

案例2:产品经理在构想新的功能时候,没有经过市场验证之前往往过度设计,逻辑功能过于复杂。上线反馈不佳后不再跟进该功能开发,既造消耗大量人力物力浪费资源,同时代码的复杂度增加维护变得更困难。利用H5进行高效开发,一步一步迭代验证功能,监测用户使用情况,实时线上调整。功能反响好就可以原生迅速跟进。

混合开发框架需要具备的几点功能

  1. 线上更新机制。增量更新,安全验证。
  2. 完善的本地控制,充分利用Native优势,实现页面跳转等基本操作。
  3. 灵活的线上控制,方便进行A/B测试,线上配置调控。

weakify和strongify探究

@weakify和@strongify是一组非常简洁搭配使用的宏,用来避免因循环引用而导致内存泄露。由开源项目libextobjc提供,被ReactiveCocoa广泛应用而进一步被熟知。

由于之前对宏不甚了解,看这两个宏的实现时非常头大。好在猫神的宏定义的黑魔法 - 宏菜鸟起飞手册给了非常大的帮助,是篇非常好的入门文章,这里就不再累述了。优雅的宏能够帮我们节省工作量,实乃居家旅行之必备神器。

@weakiy和@strongify本质上是对传统方法的简化和强化

传统的写法,获取self类型,声明weakSelf的变量并在最前面设置weak属性。