我为什么放弃移动开发

2020 年 6 月 22 日

我为什么放弃移动开发

当我还在上大学的时候,Android 和 iOS 还是新兴的平台,每个人都对这两项技术很感兴趣。如果你参加一些当时的编程研讨会,最后总会写一个小型的 Android 应用。这就是我向 Android 生态系统迈出的第一步,也可能是我随后成为了一名移动开发者的原因。


在这篇文章中,我想要分享我关于 Android SDK 和 Flutter 的糟糕体验。我提到的某些要点也适用于 iOS SDK。我已经在几年前放弃了移动开发的工作,希望后来许多事情已经在朝好的方向改进。但在当时,我发现移动生态系统是如此的令人感到困惑和挫败,以至于我选择了一条不同的职业路径。


本文由原作者发表在 medium.com,经原作者授权由 InfoQ 中文站翻译并分享



设备的碎片化


对开发者而言,Android 开发的最大痛点,就是设备配置的巨大差异。我一直都未能理解为什么 SDK 中大部分功能(尤其是用户交互界面的部分)取决于设备,而不是我的应用。这从根本上导致我必须使用支持库,针对每个目标 API 级别调试我的应用。除此之外,我还经常遇到在仿真器或者测试设备上好好的代码,却在某个三星或者华为的设备上崩溃的情况。


质感设计(Material Design)


当我在 HackerNews 或者 Reddit 上读到关于谷歌的 Material Design 的评论时,某些时刻会感到我是唯一真正喜欢它的人。我觉得它在视觉上很具吸引力,我通常很享受这样的用户体验。官方的文档网站发展得很快,也非常成功,我觉得这是优秀文档的典范。当它被宣布用于 Android 时,我感到非常兴奋!


话虽如此,在 Android 平台上从 Holo 过渡到 Material Design 并非一帆风顺。因为它好像是被急匆匆发布出来似的。在接下来的几年之中,官方的 Material Design 支持库一直缺少一些非常基本的组件。虽然你有时可以在谷歌自有的应用上看到这些组件,但是它们并没有真正被纳入到支持库中。开发者不得不构建自己的组件,或者使用 GitHub 上质量无法保证的实现作为替代品。这次使用 Material Design 支持库的经历,再加上大量的不一致的视觉设计和实现错误,让我第一次停下来真正地思考和质疑这个生态系统。



无人理会的最佳实践


构建一个可靠的 Android 应用,是一项充满挑战的任务。这主要是因为 SDK 对开发者并不友好。理论上,一个 Android 应用程序可以永远挂在后台不使用任何系统资源,然后在用户需要时立即回到先前的状态,这实在是令人惊讶。不过前提是开发者正确地实现了这个应用的状态和生命周期管理机制。


开发者:你好,互联网!我的应用在改变屏幕方向时崩溃了,该如何解决?

互联网:这很简单!禁止改变屏幕方向即可。


——啊哦,不幸的是,这种回复很普遍。


你是否曾经使用过 Java 中的线程(Threads)?在可变变量随处可见的的命令式代码库中,这件事变得非常困难。但你猜怎么着?在 Android SDK 中使用线程更加困难。如果你想要在一个 Activity 中管理 Thread,那你就只能自求多福了。幸运的是,我们最终保留了 Fragments,这最终让这件事变得容易了一些。但代价是在一开始就需要使用 Fragments。


在我作为一名移动开发者的职业生涯中,我面试了一些高级 Android 开发者。他们几乎无一例外,都很难给出这些话题的正确答案。


我一直希望谷歌能更坦然地承认这些问题,并且和社区一起解决。这些问题可能随着 Kotlin 的发布有所改善,但 Android 生态系统的根基仍然存在很多潜在的问题。


无效的设计模式和对抽象的注解(Annotation)


开发者很快就意识到,在 Android SDK 提供的抽象之上,构建一个真实世界的应用是不可能的。对此的解决方案是层出不穷的设计模式,甚至每周可能都会出现新的设计模式,我记得的包括:MVC、MVP、MVVM 和 MVI。而且由于无法使用普通的构造函数调用来管理依赖项,我们不得不在代码库的每个地方使用注解。这些本来并没有必要。Java,甚至 Kotlin,本来就有足够的能力可以对这些东西建模,更何况是以一种透明而直接的方式。但 Android 更喜欢 XML 定义和反射式实例化,因此开发者不得不在代码中使用注解和各种设计模式。实话实说,我真的无法形容这到底有多麻烦。


从未利用过的平台优势


在某种程度上,原生 iOS 和 Android 开发都是作为平台在与网页端竞争。但 iOS 和 Android 拥有只属于一家企业的巨大的平台优势,相比之下,网页端有许多利益相关者,这些利益相关者都想要根据他们的需要来影响网页端的开发。


然而,网页端拥有更加活跃和创新的生态系统。只需要想想 React 的成功故事:基于组件的用户界面,是我们目前提出的最简洁的抽象方法,这是无可否认的。多年以来,Android 并不理会这一趋势,直到最近才宣布推出“Jetpack Compose”,但是这仍然仅支持在开发者预览模式下使用。同样的事情也出现在 iOS 开发中。


所以,现状是我们仍然需要继承 android.view.View 类,这个类有 1.5 万行代码,和数十个生命周期函数,但同时我们还要尝试注入自己的 merge XML 文件。iOS 和 Android 本来可以成为这个竞争中的引领者,但实际上,它们已经被远远甩在了后面。


请不要对 UI 开发抱以希望


一个精美的应用的关键在于用户界面(UI)。我在上文已经吐槽了不少关于组件的问题,但这些还不是最严重的。你是否曾经调试过网站上的故障?通常的操作是:打开浏览器的开发工具,点击有问题的元素,然后使用 CSS 和 HTML 的属性来调试。与此相比,Android 是一个无法访问的黑盒。老实说,我一直没有完全理解 Android 的主题和样式机制,并且与 Web 相比,Android 的工具显得毫无用处。


想要在这个框周围添加阴影吗?没问题,请使用这个奇怪的.9.png文件,或者依靠API Level 21,你就可以正确渲染阴影了(尽管只有凸形阴影)。

不好意思,你忘记实现自定义视图四个构造函数的其中一个了。但我不会抛出编译错误,我只会在运行时崩溃!

现在有支持超高屏幕密度的手机了。可以在应用里添加 xxxhpi的assets吗?不行,不支持矢量图,我们做不了这个。

——来自Android SDK的深夜独白


矢量图


在 Android 21(5.0)之前,Android 平台根本不支持正确的矢量图。这背后的原因是,多样的 Android 设备导致了多种不同的屏幕密度,这要求图像针对每种屏幕密度都做仔细的调整。务实的开发者自然而然地开发了转换矢量图的工具,将 logo.svg 转换成 ldpi/logo.png,mdpi/logo.png,hdpi/logo.png,xhdpi/logo.png,xxhdpi/logo.png 以及 xxxhdpi/logo.png。幸运的是,最终谷歌改变了它们的想法,并提供了 VectorDrawble 来支持部分可缩放矢量图形(SVG)。的确,这足够减轻当时的痛苦。但仍然令我困惑的是,一个以能够在任何设备配置上运行为优势的开发环境,是如何在这么长时间都不支持矢量图的情况下活下来的?


死局


这些年,我开始越来越担心我的知识会在不远的将来过时。我学到的大多数知识都是 Android 开发所特有的,很少适用于更广泛的软件开发领域。考虑到这些方面,我不认为原生的移动开发会一直存在,所以我开始担心所学到的技能的实用性。


Flutter


当 Flutter 发布时,我非常激动。它承诺将解决一些主要的 Android SDK 的缺陷,同时无偿提供跨平台支持。所以在我上一份工作中,我们开始从原生 Android 迁移到 Flutter 上。我必须承认,Flutter 信守了它的承诺:


  • Flutter内置的渲染流水线完全解决了Android的碎片化问题。

  • 从一开始,它就提供了详尽的高质量的Material Design组件库。

  • 热重载功能的灵活性完全颠覆了我的认知。

  • 你能获得前所未有的高质量界面外观的跨平台体验。


但不幸的是,它也不完美。而且有点可惜的是,Flutter 遇到的问题本可以通过一个全新的项目轻松避免。


  • Dart很糟糕:它还是一门相对年轻的语言,但它重蹈了不少它的前辈的覆辙(错误的类型系统,Null,使用语句而不是表达式,等等)。

  • Flutter SDK中让人不解的设计决策:它们本应创造一个更好的React,但却创造了一个更糟糕的。本可以通过简单的函数调用解决的问题,往往需要通过有状态的面向对象编程(OOP)机制才能解决。(我记得对话框的路由和处理在这个方面尤为痛苦)


结论


在某一时刻,我清楚的意识到,我不想在这种技术上倾注心血了。我向自己许诺,绝不再在移动平台上编程。一个设计精美的、响应式的网站在今天已经可以给你足够好的体验,所以这是我的不二之选。只需要一个代码库,它就能适用于每个客户端。如果我还是不得不构建一个移动应用程序,我仍然会选择 Flutter,甚至是在我仅针对 Android 的情况下。我绝对不会再使用 Android SDK。


话虽如此,但要澄清一点,我还是非常喜爱和欣赏精心制作的原生应用的(无论是在移动设备上还是桌面上)。我对那些使用现有工具就能创建出这样的应用的开发者,致以崇高的敬意。只是,我不想再成为他们中的一员。


原文链接:


9 reasons why I gave up on being a Mobile Developer


2020 年 6 月 22 日 10:009219

评论 5 条评论

发布
用户头像
已转行
2020 年 07 月 21 日 15:43
回复
用户头像
做了6年的android工程师,从个人的经历来讲,好的移动开发要适应项目,甚至是公司。例如我在上一家产品研发型公司,我能把app页面流畅度做到秒开,内存做到实时的回收等,但是现在这一家产品+项目性公司,甲方的要求就是坨屎也得跟他实现的情况,抱歉,牺牲是在所难免的。但是大家都高兴了(当然我是希望能够做的更好一些)。
2020 年 06 月 30 日 22:30
回复
用户头像
作者的含义是用H5比较好?看下 www.appkuang.com
2020 年 06 月 28 日 09:47
回复
用户头像
“老实说,我一直没有完全理解 Android 的主题和样式机制”--同感
2020 年 06 月 26 日 21:14
回复
用户头像
有道理的。
2020 年 06 月 24 日 10:19
回复
没有更多评论了
发现更多内容

打通IO栈:一次编译服务器性能优化实战

AI乔治

Java 编程 架构 io 高性能

架构师训练营第四周命题作业

一马行千里

命题作业 架构师训练营第 1 期

架构师训练营第四周学习笔记

一马行千里

学习笔记 架构师训练营第 1 期

Java-技术专题-纤程库Quasar

李浩宇/Alex

为什么学习总是停在开头两页?

Nydia

年轻代频繁ParNew GC,导致http服务rt飙高

AI乔治

Java 架构 JVM GC 编程学习

芯片破壁者(十七):“硅谷市长”罗伯特•诺伊斯开启的产业法则

脑极体

重大事故!IO问题引发线上20台机器同时崩溃

AI乔治

Java 架构 多线程 io 并发

Netty源码解析 -- 客户端启动过程

binecy

Netty nio 源码阅读

区块链跨境支付系统开发源码,承兑系统搭建

WX13823153201

怎么才算掌握了JDK中的线程池

AI乔治

Java 编程 架构 jdk 线程池

一个草根的日常杂碎(10月14日)

刘新吾

随笔杂谈 生活记录 社会百态

华为卢毅权:品质专线2.0 打造无处不在的品质联接

Geek_459987

程序员黄金年龄25-28岁,我们30+的人该去哪儿?附华为案例;

Java架构师迁哥

一次线上JVM调优实践,FullGC40次/天到10天一次的优化过程

AI乔治

Java 编程 架构 JVM GC

代表Java未来的ZGC深度剖析,牛逼!

AI乔治

Java 架构 ZGC JVM GC调优

12张图带你彻底理解分布式事务产生的场景和解决方案!!

冰河

分布式事务 2PC 可靠消息最终一致 TCC 最大努力通知

使用Spring Boot创建docker image

程序那些事

Docker spring Spring Boot Spring Boot 2

甲方日常 31

大橘子

工作 随笔杂谈 日常

架构师训练营第 1 期第四周课后练习题

Leo乐

「架构师训练营第 1 期」

系统架构--作业

Nick~毓

如何优雅的搞垮服务器,再优雅的救活

MySQL从删库到跑路

Linux 升级glibc 启动异常 无法进入系统 抢救模式

numexpr:你以为numpy已经够快了,其实它还可以更快

计算机与AI

Python 机器学习 数据分析 Numpy

华为:“智能分布式接入网”打造真千兆高品质生活体验

Geek_459987

架构师训练营第四周作业

脸不大

华为发布“品质专线2.0&智能分布式接入”解决方案

Geek_459987

Flink周期性水位线分配器-6-3

小知识点

scala 大数据 flink

一次百万长连接压测 Nginx OOM 的问题排查分析

AI乔治

Java nginx 架构 服务端 高性能

算法图解:如何找出栈中的最小值?

王磊

Java 数据结构 算法

一个草根的日常杂碎(10月12日)

刘新吾

随笔杂谈 生活记录 社会百态

一个草根的日常杂碎(10月13日)

刘新吾

随笔杂谈 生活记录 社会百态

我为什么放弃移动开发-InfoQ