Glow 技术团队博客

Glow 技术团队博客

Thoughts, stories and ideas.

swift

Swift 3

Swift 3 正式发布已经 3 周了,大家 Swift 项目的代码迁移做的怎么样?Glow Baby 项目我花了近 3 天时间,12956 行增改,9817 行删减,360 个文件。迁移的过程是痛苦的,心很累,Xcode 8 的迁移工具也没有让我轻松多少。 不过待迁移完毕后,Swift 3 读起来、写起来都更舒服。Swift 1 确立了语言的基线:安全、快速、现代。Swift 2 展现了 Swift 应该是什么,未来怎么走:面向协议的编程、开源。而 Swift 3 更多是清扫和规范:新的 API 设计简洁干净,
  • 顾 鹏
    顾 鹏
android

谈谈移动应用的安全性实践

作为一家大数据公司,Glow不仅重视用户的数据,更加注重数据的安全性。 本文将从用户注册流程出发,逐步介绍我们在提高数据安全性方面采用的一些策略方法,供读者参考。下面将从 Android 和 服务端 两部分来进行讲解。 从注册说起 用户第一次打开app时便会进入注册页面,然后客户端会要求用户输入用户名、密码并传递给服务端去创建一个新的user。此时若通过明文传递用户名密码便是一个安全性隐患。或者说,如果有人监听注册API,那么很快就可以窃取到很多用户的账户数据,而且可以偷偷利用这些账户信息随时获取甚至更改用户数据。 这对于任何一家企业而言都是非常可怕的。 全站Https 因此,为了应对数据明文传输隐患这个问题,我们在自家所有app中都采用了Https方式通信。在Android端我们采用了Square家的OkHttp3作为网络层,为应用层提供Https服务。 下面先对Https的基本工作原理进行下介绍,以便后文的讲解。 1. 首先,客户端去请求服务端的数字证书,这个证书包含了一个公钥。该证书购买后存储于我们自己服务器上。 2. 当服务端收到客户端请
android

Android里巧妙实现缓存

为了快速查询会被多次调用的数据,或者构建比较废时的实例,我们一般使用缓存的方法。缓存的基本概念大体上差不多,这里就不再重复,有兴趣的可以查看维基百科的介绍。 缓存有很多的实现方式,技巧性还有坑都很多,今天我给大家介绍一些非通用的方法,可以巧妙地帮大家简单实现一些内存缓存。 Supplier和Memoize SQLite是Android里常用的一种数据存储方式,在访问数据库数据时需要通过SQLiteOpenHelper。 一份好的数据库连接代码应该能解决以下几个问题: a) 构建实例比较费资源 b) 数据库连接最好能复用 c) onUpdate等方法在执行时不能和其他实例构成冲突。 这里可以很简单的这样写 Suppliers.memoize(new Supplier() { @Override public SQLiteOpenHelper get() { return new ...; } }) 这段代码利用了Guava提供的一些辅助方法实现Supplier和Memoize和逻辑。顾名思义,Supp
  • 刘聪
    刘聪
ios

当 NSDictionary 遇见 nil

Demo project: NSDictionary-NilSafe 问题 相信用 Objective-C 开发 iOS 应用的人对下面的 crash 不会陌生: * *** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1] * *** setObjectForKey: key cannot be nil * *** setObjectForKey: object cannot be nil Objective-C 里的 NSDictionary 是不支持 nil 作为 key 或者 value 的。但是总会有一些地方会偶然往 NSDictionary 里插入 nil value。在我们的项目开发过程中,
  • Allen
    Allen
server

Glow Cache 构架

作为一家大数据公司,Glow每天都会收到海量的数据。这些数据的快速存取,是必须面对的一个问题。Cache,则是众多解决方案中,最实用的一个。笔者将给大家介绍一下Glow的Cache框架,希望能对广大创业团队有所帮助。 什么是Cache Wiki上说:a cache is a component that stores data so future requests for that data can be served faster 在绝大多数服务器框架中,就是用内存代替数据库,以达到提高速度的目的。 传统的Cache有两种结构,write-through和write-back。 * write-through:一个写操作(write)同步更新cache和backend storage * write-back:一个写操作(write)只更新cache,当再有变化发生时,写回backend storage 显然,write-back更高效,但更复杂。作为创业公司,
devops

生产环境下的性能监控 - Datadog

排查性能问题往往比排查功能性的Bug更让人头疼,主要有以下几个原因 * 很多性能问题只会在高负载的生产环境下出现,在开发过程中很难发现。 * 功能性出错时我们通常会抛出异常,我们可以通过Tracestack很快定位到问题所在代码的位置。但对于性能问题,我们很难做这样的快速定位。 * 虽然我们有各式各样的Profiling工具,但适用于对生产环境的并不多。当然这因编程语言而异,Glow服务器端的技术栈是Python + Gevent,目前为止我们都没有找到合适的Profiling工具。 对于服务器端的性能问题,我们常用的方法是写日志文件,例如把每个请求的响应时间都记录下来,但对海量日志文件的存储,聚合与分析又成了另一个麻烦。常用的解决方案有ElasticSearch + Logstack + Kibana,或是StatsD/CollectD + Graphite等等。在Glow,对于性能监控这样的通用服务,我们更偏向于选择云服务,而不是自己去维护这些系统,这样我们的精力才能集中在产品研发上。 在对于性能监控类的云服务做了一些横向比较后,我们选择了Datadog,使用一年
Service Oriented 的 iOS 应用架构
ios

Service Oriented 的 iOS 应用架构

Intro 前不久我们上线了一款新的 App - Glow Baby,App 针对 0 - 12 个月大的新生宝宝,提供爸爸妈妈全面、健康、科学的育儿知识,帮助记录宝宝成长的点点滴滴。在 Glow Baby 的开发中,我们也做了一些新的尝试 - 使用 Swift 开发,并基于 Swift 的语言特点设计了新的 iOS App 架构。 除了 Community 这部分的代码是作为一个私有的 Repo 引入,Glow Baby 基本是 100% Swift 代码。Glow Baby iOS 团队都是第一次接触 Swift,过程中我们踩过很多坑,遇到过很多抓狂的问题。但总体上,
  • 顾 鹏
    顾 鹏

Redshift as data warehouse

Glow 的 server infrastructure 全部搭建在 AWS 上,一般要选择一些基础服务的时候,总是先看 AWS, 只要功能和成本符合要求,不会特意选择开源方案。 数据仓库我们选择了 AWS 的 Redshift. 在一年多的使用过程中 Redshift 的性能和稳定性都不错, 当然也有一些坑, 这里整理下在使用 redshift 的过程中的一些经验和遇到的问题. Columnar storage 就是常说的列式存储, 这里只谈应用场景, 理论详情可以看: http://docs.aws.amazon.com/redshift/latest/dg/c\_columnar\_storage\_disk\_mem\_mgmnt.html 常用的开源数据库 MySQL 和 PostgreSQL 都是传统的行式数据库, 和 columnar
  • Will Xu
ios

Deferred Deep Linking in iOS

Deep Linking 其实 deep linking 并不是一个新名词,在 web 开发领域,区别于指向首页的链接(http://tech.glowing.com/),deep linking 是指向具体内容页的链接(http://tech.glowing.com/cn/advices-to-junior-developers/)。在移动开发领域,deep linking 则是指 mobile app 在 handle 特定 URI 的时候可以直接跳转到对应的内容页或触发特定逻辑,而不仅仅是启动 app。比如 dianping://shopinfo?id=1859284,如果你的手机上装了大众点评的话点击这个链接可以直接跳转到商铺页面。这样做的好处主要有: * 在 web 和 app 的切换过程中保留上下文 * App 间带上下文切换(
  • Allen
    Allen

动态Android编程

注意:本文章有些例子需要对Java或Android有一定编程基础。 与Python相比,Java是一门比较严肃的语言。作为一个先学Python的程序员,做起Android难免会觉得不舒服,有些死板,非常怀念decorator等方便的方法。为了实现一个简单的逻辑,你可能需要写很多额外的代码。 举个例子,做数据库查询时,怎么从一个Cursor里取出类型为User的实例到List? 假设User是这样的 class User { int id; String name; } 1. 找出User对应所有的列和每列在Cursor对应的索引。 2. 如果索引存在,根据类型取出正确的值。 3. 对于每个属性,不断重复上述步骤取出对应的值。 { int columnIndex = cursor.getColumnIndex("id"); if (columnIndex >= 0) { instance.id = cursor.getInt(columnIndex); } } { int columnIndex = cursor.
  • 刘聪
    刘聪
devops

写好DevOps的文档

每个DevOps都一个百宝箱,里面放着各种命令行脚本,可以用来自动化各式任务。但若文档不全,即便是脚本的作者,时间一久也不敢随便乱用,毕竟运维的大部分工作是管理生产环境,要是出了错,不是轻描淡写就可以蒙混过关的。写好DevOps的文档其实也是一门技术活儿,这里给大家分享一些组织运维脚本及其文档的经验。 Fabric的任务管理与文档 在以前的文章中,我们曾经介绍过Glow使用了fabric来执行各种日常管理的任务。Fabric提供了非常好用的任务组织以及查阅任务文档的功能。 Fabric的主文件一般命名为fabfile.py,但任务多了,都写在一个文件里显然很难维护。Fabric有一个很实用的特性,就是当fabfile.py里导入其他模块时,会自动发现里面的fabric任务。利用这个特性,可以把各种任务分类写在不同的模块中,然后在fabfile.py中统一导入。比如Glow的DevOps代码库的结构大概长这个样子 $ tree ├── __init__.py ├── fabfile.py ├── fab_scripts │   ├── __init__.py │   ├
ios

实现iOS 9 Task Switcher动画

升级到iOS 9以后,发现新的task switcher的动画蛮有趣的,于是就动手实现了下,最终效果如下~ 思路 1. 首先我们需要一个横向的scroll view,可以用UICollectionView,也可以自己实现一个。scroll view里每一页都是一张card,一屏5张card: | | |card card card card card| | | 2. 其次,我们需要在scrollViewDidScroll中判断每张card距离中心的距离,根据这个值来调整它的alpha,scale以及x轴的translation。 alpha:右边的card alpha都是1,左边的越靠左alpha越小 scale: 从左往右依次变大 translation:除了中间的card,所有的card都会右偏,而为了让中间card大部分都露出来,右边的card偏移需要比左边大 开工 1. 横向滚动的scroll view 我们可以自己实现一个横向无限滚动的
  • leo
    leo

开发 Apple Watch 应用

之前跟两个同事一起用业余时间给我们的 Glow App 做了 Apple Watch 的应用。写这篇文章来对 Apple Watch 的开发做个介绍,也列出开发过程中遇到的一些坑。虽然 Watch OS 2 已经出来,而我们是用 WatchKit 进行的开发,但很多内容也适用于 Watch OS 2。希望这篇文章对大家有帮助。 Introduction * Design * WatchKit App Architecture * Data Communication * Provisioning Profiles and Entitlements * Tips Design 本质上,你可以把 Apple Watch 当作 iPhone 的一个扩展屏幕。你不需要掏出手机。只需要稍稍抬一下手腕,就可以获取信息,或做一些简单的操作。实际上,
  • 顾 鹏
    顾 鹏

Python中的时区处理

我们要什么? 当一个应用的用户遍布全世界的时候,程序的代码少不了要和时区打交道。服务器端针对用户的定时任务需要定到用户所在时区的时。 在Glow Nurture中,比较典型的一个例子就是:如果用户没有记录服用Prenatal Vitamin,两天后晚上9点给用户发送程序内通知提醒服用Vitamin。 翻译成直白的程序需求就是:获取某用户所在时区某年月日21点对应服务器所在时区的时间戳。 Python提供了什么? Python 提供了datetime, time, calendar模块,然后感谢Stuart Bishop stuart@stuartbishop.net, 我们还有pytz可以使用。 由于存在datetime模块,time模块,在datetime模块下又存在datetime类,time类,为避免阅读上的误解,以下说到time, datetime时指模块,datetime.time, datetime.datetime指datetime模块下的time类和datetime类。 datetime模块定义了如下类: datetime.date
  • Eric Xu
career

如何提升你的能力?给年轻程序员的几条建议

一转眼工作已有8年,前两天公司一位初入职场的同事希望我给一些建议与经验。我觉得这个话题很有价值,这里以个人的想法与经历写成此文,希望给年轻的开发者们一些启发。 我工作过的公司有4家,NVIDIA, Google, Slide和Glow。其中两家是知名的大公司,Slide我是D轮过后加入的,那时约150人。Glow则是从它第一天创立,一直走到现在。个人的工作也从Developer,Tech Lead,Engineering Manager到CTO。这些经历使我对程序员的个人发展之路有比较全面的看法。 如果你问一个年轻的前端开发人员,你在今后的3年内如何提升自己的能力?他可能会说“我现在对Web前端比较熟悉,但我想深入了解AngularJS,另外React现在发展的很快我也想看一下。之后,我会花时间去学习iOS和Android开发。”看上去不错,但缺乏系统性的目标。或者说,他制定了学什么,但对为什么要学这些并没有仔细的思考。 在技术领域,有太多的东西会迅速的过时,如何利用有限时间,最大化你的长期收益?这里我可以给出几条建议 打造你的工具箱 工欲善其事,必先利其器。每个
calendar view

GLCalendarView - a Fully Customizable Date Range Picker

GLCalendarView是Glow的第二个开源项目,虽然开源的calendar有很多,但是支持range的却很少,我们对GLCalendarView的定位是date range picker,希望它可以帮助到其他开发者~ Demo Installation CocoaPods 如果你使用cocoapods,那么只需将GLCalendarView加入PodFile pod "GLCalendarView", "~> 1.0.0" Source File 或者可以将 Sources 目录下的所有文件拷贝进项目 Usage * 在storyboard里放置一个view,或者用代码创建,将view的class设置成GLCalendarView * 在viewDidLoad里, 对calendar view进行一些设置,例如设置 firstDate 和 lastDate * 在 viewWillAppear里, 设置需要显示的ranges,调用 [calendarView reload]; 来刷新数据 如果要在calendar vi
  • leo
    leo
python

轻量化运维之一 Fabric

其实在Glow的技术团队中是没有全职的Ops或是Sys admin,我想很多小的创业团队也是如此。但是运维是整个产品发布过程中必不可少的一环,所以想写一个针对开发工程师(特别是Python工程师)的运维入门教程。如果你是专业的运维工程师,请不要浪费你自己的时间。 先说一下,什么是“轻量化运维”?简而言之,就是用最快最省事的方法做好最基本的运维工作。这里的工作主要包括以下几个部分 1. 生产环境服务器集群的日常管理 2. 自动化系统配置与代码发布 3. 系统状态与性能监控 今天先来聊聊服务器的日常管理。这里包括各种琐碎的任务,例如重启服务,安装或是更新软件包,备份日志文件或是数据库等等。通常对于这类任务,我们要解决两个问题 * 针对每项任务编写脚本,避免重复劳动。虽然许多运维都是Shell脚本达人,但大部分程序员看到Shell脚本都是一个脑袋两个大。 * 需要在许多台机器上执行同一项任务。 如果你碰巧对Python略知一二,那么恭喜你,从此以后你只要使用Fabric这个神器,就再不用为Shell脚本头痛了。 Fabric初探 - 执行单条指令 Fa
android

Nurture 安卓版中的婴儿动画是怎么实现的?👶

Nurture是我们为准妈妈专门准备的app。在app首页有一个炫(dāi)酷(méng)的婴儿动画。这篇blog就来聊一聊这个动画是怎么实现的以及我们走过哪些坑。 如果你还没有亲手体验过这个动画,你可以戳下面的链接下一个感受一下: * iOS 版下载 * Android 版下载 动画格式 婴儿肢体动画的制作使用的是 Flash 并导出为 LWF格式。这样做的优点是对于设计师来说,所设计的动画在最终的产品的效果基本上是完全一样的。 LWF 官方提供了基于 UIKit 的渲染器,所以在 iOS 上工作完全没问题。不过因为其并没有直接提供 Android 的支持,所以我们在 Android 版本的开发中就遇到了坑。 尝试过的方案 我们尝试过下面几种方案: * 使用视频文件代替。 但是因为支持透明通道的视频格式不多,而且转换出来效果也不好,所以最后并没有使用这个方案。 * 使用 Pure2D。 Pure2D 是一个纯Java的游戏引擎,而且LWF提供官方支持(因为是一个人写的)。不过这个引擎的文档和成熟度都让人很着急,最后不得不放弃。 * 使用
ios

动态修改UINavigationBar的背景色

这是我们最终想要得到的效果: 思路 在UISrollView的delegate方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView中根据当前的contentOffset更新navigationBar的backgroundColor即可,so easy~ 开动 那么我们来看看apple为我们提供了哪些API来设置navigationBar的颜色。 首先想到的是最常用的[UINavigationBar appearance] ,我们一般会在AppDelegate中使用它对navigationBar进行统一的设置。但是如果试一下,会发现在scrollViewDidScrollView中调用它并不能动态地改变navigationBar的颜色,原因可以看一下Apple的doc: Use the UIAppearance protocol to get the appearance proxy for a class. You can customize the appearance of inst
  • leo
    leo
ios

GLPubSub - Glow iOS 中的订阅发布模式

前言 我们计划通过 blog 和开源的方式,分享一些我们在开发 Glow 和 Nurture 的过程中积累的开发经验。GLPubSub 作为开源计划的第一步,是一个代码量较少,但很实用的 Category。 GitHub: https://github.com/Glow-Inc/GLPubSub Documentation: http://cocoadocs.org/docsets/GLPubSub Notification 作为发布订阅模式(观察者模式)的一种,在 iOS App 的开发过程中很常见,GLPubSub 是 NSNotificationCenter 的封装,目标是简化 iOS 开发中的发布订阅模式。因为是 NSObject 的 Category,所以可以在任意 NSObject 的子类上使用。 安装 CocoaPods
  • Allen
    Allen
ios

使用CADisplayLink实现果冻效果动画

CADisplayLink是什么 根据Apple的doc: A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display. 比起NSTimer,CADisplayLink可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性。 Demo 我们希望在animate一个view的时候给它加上果冻效果: 我们会把所有的逻辑都封装到一个BlockView里,在这个view里首先申明一个property: @property (strong, nonatomic) CADisplayLink *displayLink; 在动画开始的时候,初始化displayLink,指定tick方法: - (void)startAnimation { if (self.displayLink == nil) { self.
  • leo
    leo

如何自己动手实现 KVO

本文是 Objective-C Runtime 系列文章的第三篇。如果你对 Objective-C Runtime 还不是很了解,可以先去看看前两篇文章: 1. Objective-C Runtime 2. Method Swizzling 和 AOP 实践 本篇会探究 KVO (Key-Value Observing) 实现机制,并去实践一番 - 利用 Runtime 自己动手去实现 KVO 。 KVO (Key-Value Observing) KVO 是 Objective-C 对观察者模式(Observer Pattern)的实现。也是 Cocoa Binding 的基础。当被观察对象的某个属性发生更改时,观察者对象会获得通知。 有意思的是,你不需要给被观察的对象添加任何额外代码,就能使用 KVO 。这是怎么做到的?
  • 顾 鹏
    顾 鹏

Method Swizzling 和 AOP 实践

上一篇介绍了 Objective-C Messaging。利用 Objective-C 的 Runtime 特性,我们可以给语言做扩展,帮助解决项目开发中的一些设计和技术问题。这一篇,我们来探索一些利用 Objective-C Runtime 的黑色技巧。这些技巧中最具争议的或许就是 Method Swizzling 。 介绍一个技巧,最好的方式就是提出具体的需求,然后用它跟其他的解决方法做比较。 所以,先来看看我们的需求:对 App 的用户行为进行追踪和分析。简单说,就是当用户看到某个 View 或者点击某个 Button 的时候,就把这个事件记下来。 手动添加 最直接粗暴的方式就是在每个 viewDidAppear 里添加记录事件的代码。 @implementation MyViewController () - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Custom code // Logging
  • 顾 鹏
    顾 鹏
objc

Objective-C Runtime

Objective-C Objective-C 扩展了 C 语言,并加入了面向对象特性和 Smalltalk 式的消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。 Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递 (Messaging)。 消息传递(Messaging) I’m sorry that I long ago coined the term “objects” for
  • 顾 鹏
    顾 鹏
android

代码规范和Android项目中的一些可用工具

这里主要讲一下关于代码规范的相关问题,和在Android项目中如何利用一些工具进行规范和检查。代码规范不是一个Android项目特有的问题,所以前部分内容是不单针对Android的。 什么是代码规范? 代码规范一般是指在编程过程中的一系列规则规范。 一般来说代码规范可以分为两种。 1. 一是编程语言本身在设计时所规定的一些原则,这类规则大部分都是强制的,像Python里用缩进表示逻辑块,Go里用首字母大小写表示可见度。 2. 另外一种是在一些组织约定的一些规范模式或个人在编写代码时的一些偏好,这种一般都是非强制的。比如大括号是放在方法名的同一行呢还是另起一行,不同的人有不同的想法,我也不知道谁好,所以别问我。 假如是强制的,大家暂时也不能反抗,只能吐嘈吐嘈,我们需要关心和规范的是非强制性规范。 一般情况下代码规范应该包括以下东西: 1. 代码格式和要求:注释,缩进,空格,空行 2. 约定的方法名,变量名,类名等等取名相关问题 3. 通用的一些模式和一些要避免的模式 为什么要有统一的代码规范? 假如你一个人单干,并且基本上也会这么继续下去
  • 刘聪
    刘聪