当前位置: 首页 > 编程日记 > 正文

[转]Android敏捷开发指南

原文地址:http://www.apkbus.com/android-72730-1-1.html

本文紧密结合移动开发方法与技术,围绕Android平台的开发探讨提供更高质量移动产品的解决方案。作者在文中分析了移动开发中常见的问题,从两方面阐述了ThoughtWorks(???)使用的测试开发方案和相应的架构方法与常用工具应用,并进一步阐述了为移动开发流程所提供的持续发布方案。

随着云计算、移动互联等一系列新技术概念的崛起,新一轮的IT经济正在不断扩大发展。带来无限机遇的同时,也提出了许多有别于传统开发的挑战。近几年来,我一直在尝试各种移动项目,虽然它们在应用领域、技术类型以及工作模式等方面各不相同,但我在摸索中逐渐总结出了一些比较具有共性的问题。

移动项目中的常见问题

为了实现较好的用户体验,反复的设计与验证导致产品发布时间延长。移动应用由于其多样性的应用场景,使产品设计侧重于适应不同目标的展现方式与操作习惯。设计实现的方式与使用用户群、企业服务模式、新的科技实现手段,以及各种碎片分化(???)的目标支持设备等一系列因素密切相关。在产品实现初期,许多的内容和形式都需要在已有开发原型的基础上,进行紧密结合用户体验的测试。不少团队花了很长时间完成了目标,可测试后又要经历反复且大量的修改。这对产品的如期发布提出了巨大的挑战,发布时间也会因此一拖再拖。 即便是产品磕磕绊绊地发布了,设计的改变往往也是最让人头痛的问题。

图1 某产品四个阶段首页面对比图

市场导向性强,业务需求变化快与缩短产品交付周期需求之间产生矛盾。经过了一系列的市场分析、产品设计、项目研发过程后,一个移动产品终于投放到了市场。但这完全不能看做是一个项目的交付完成,恰恰相反,这只是一个新阶段的开始。在残酷的市场竞争中,用户不是产品的被动消费者,而是需求的提出者,会在各种下 载市场(例App Store、Google Play)发出评论对应用进行评估,从而直接影响应用的市场占有率。同时随着一系列用户体验数据的收集分析和整理,业务部门的需求递增,新功能点开始一个 个被搬上研发经理的台面。这给开发团队应对需求改变以及对递增的代码结构升级能力提出了更高要求。图1展示了一个产品在过去一年多时间里首页面的变化。

可以看出在项目所经历的四个比较大的阶段中,仅一个首界面的功能,也经历了从最开始的普通列表界面,到后来增加地图功能、书签的过程。在第四个阶段中,为了满足用户注册登录等需求,首页面还进行了基于左侧滑动菜单的导航转型与登录反馈等的功能扩充。每个重大阶段的转型,都来自最真实的市场评论数据,并结合 Omniture(通过收集用户数据行为分析的工具)等产品的体验数据分析与业务增长需要进行开发。

为了实现更加精细的体验效果并兼容 Android的各个版本(例如图1中列表和地图间的切换需要通过动画三维翻转实现等),所有这一切都必须在同一个Activity内完成交互。这给大量的页面逻辑、状态和视图层级关系的升级改造带来了很大的难度。与此相对应的坏消息是,移动应用对短周期的快速发布有着强烈的需求。即使是一个好的应用,如 果没有及时保持稳定频率的更新,很快就会被接踵而来的竞争者追赶,最后落到被用户遗忘的境地。从某种角度讲,除了产品新功能的推出外,应用程序的更新也具 备某种广告的职能,去强化品牌在消费人群中的地位,稳定和扩大市场的占有率。

移动团队虽小,但要求更良好的产品集成性。同一个产品,一般根 据支持平台的数量以及并行发布需求,配置有多个小团队和数据整合(API)团队。每个团队的开发因为进度不同和平台特点的不同,往往在整合过程中提出各自不同的集成需求(包括数据集成和逻辑集成),例如Android的内存性能不好,要求服务端的图片质量与剪裁要和iOS有所区别;再例如有时为了降低网络 性能对体验的影响,会更改设计,将逻辑分散在API整合段和设备端。这就为团队间的整合埋下了风险。事实上,这在多团队的并行开发中,并不是个别现象。

多样化的设备和版本、长期的维护开发,带来快速升高的测试成本。随着开发功能的增加,页面布局、操作响应和交互处理大量逻辑模块增加,以及越来越分化的设备 和系统版本,给测试工作带来了相当大的难度。在之前我做咨询时,一个项目经理告诉我,他有一个运行了一年半的项目,当时还有一周就要上线,可仍有60个Bug,5名测试工程师因为对质量没有信心而不停加班,开发也为修改一个个错误都头痛不已。

通过技术方案寻求解决途径

为了解决上述常见移动项目的问题,在项目实践中,我们试图通过合理地运用技术方案来帮助完成高质量移动软件的目标。

实现高可维护性的代码,减少代码扩展过程中的腐化和变动带来的副作用。随着功能增加,越来越多的逻辑模块被堆砌在同一个单元内,导致代码可读性下降,维护复杂度提高。这时的修改都存在破坏原有功能的潜在风险。

如果解决这两个问题,将在很大程度上提高应用在开发过程中对产品需求改变和开发周期控制的适应能力。实践中,我们使用元素组件化开发和测试驱动开发解决方 案。组件化的基本目的就是将代码的可读性置于编码过程中,通过形成独立子元素组件来代理自身的功能逻辑,并以此结构化XML的布局资源,提高可读性。同 时,通过测试驱动的开发方式为代码的粒度质量提供原始保障,让代码演进过程减少编码副作用破坏其他功能的现象,从而提升代码的可维护性。

通过功能自动化测试,保证开发过程中测试成本的相对稳定和质量保障。这里要分两个部分来谈。第一部分是通过提高自动化测试的比例,减少由人工重复完成的测 试。在应对多平台、多版本、反复回归测试时,自动化测试对质量的保障就显得尤为重要;第二部分是由于对需求理解偏差,产生的质量问题和因此增加的返工。这 里就需要引入基于业务行为驱动开发(BDD)的自动化测试管理。让需求成为可验证的执行代码,将会巨大限度的缩小业务需求、开发和测试之间的鸿沟。

当然,我在从事多个项目开发咨询的过程中,也曾遇到大量的需求变更,导致自动化测试废弃,从而提高成本的案例。这时往往要注意协调自动化测试金字塔,即单元测试、功能测试、UI界面测试等几部分的比例关系,实现质量与成本的平衡。

让随时可工作的产品来提高团队的交付能力。面对不断变更的需求与任何时候都可能出现的产品延时,提高团队的整体交付能力,就显得格外的重要。作为重要一环的持续集成和可用多点环境下测试,便成为这其中不可或缺的重中之重。而如果产品的各个平台都可以保证相对稳定的持续集成与发布,那么这样的方案也自然成为消 除团队合作壁垒的重要技术保障。

加快用户体验验证周期,增加修改频率降低单次修改的调整规模。优秀的用户体验,永远是前端工程师最关心的部分。这就需要能够尽早地去做更深入的分析与验证,更快地发现问题,并接进行修改与调整。同时缩短反馈回到开发端的周期,将大大降低代码的修改难度,提高产品效率。而自动化的编译、集成与部署操作流程就是用一个非常有效的方法来完成闭环回路。可持续集成与部署技术为缩短周期提供了根本上的保证。

刚刚提到了许多用来移动项目问题的解决方案。那么下面就让我们来看看在Android开发领域,这些方案是如何具体实施的。

结构化组件

所谓组件化就是将应用内部的UI元素充分拆分成相互独立子部件(例如常见的Android的Widget组件)。大的子部件由多个小的子部件组成。

这样的好处是除了在代码层面上更易于修改外,同时也通过对类和方法的命名实现了XML代码的结构化。图2作为一个简单的示例,大致表现了图1中第四个阶段首页面的组成方式。可以看出XML代码中的每一个子组件都是一个相应的视图组件,这些组件通过Java类和XML的对应完成一个子视图功能。XML中大体可 以表达出页面视图的一个可读性组成方法,而对应的Java文件则代表了每个视图的生成细节模型和交互响应逻辑。

另外需要说明的是,我们曾尝试了多种消息传递机制。最后证明,组件的单一顺序传递是一种相对最稳定和易理解的传递方法,子视图的交互消息只能传递给其父视图,然后由父视图传递给其他 子视图。即如图2中ContentRotableScreen接收到一个自己不能处理的响应事件,应该将消息传达给SlidableContainer, 再统一分发给需要处理事件的NavMenuScreen作相应的动作。

dda9_503b381343736.jpg

图2 某产品四个阶段首页面的组成方式

这样做既保证了消息传递的准确性,又维护了一个统一的代码结构,方便实现代码的可读性和可维护性。

单元测试工具

单元测试是测试驱动开发的主体测试构成,旨在从代码粒度上实现对应用质量的把握,是可维护性代码的核心。其具体粒度大小取决于在代码出现问题后,能在多大程 度上准确定位问题。这也是单元测试最大的意义所在。这份意义所带来的是更高的代码可维护性、更稳定的代码可重构性、更便捷的可扩展性。而这一切为稳定结构 变化、减弱代码腐化影响、技术改进所带来的代码变更奠定了良好的基础。

为了实现比较良好的单元测试,需要一系列代码结构优化和测试工具使用的辅助。

在做深入说明Android系统开发结构之前,先来看一下在该平台开发时所常见的工具和相应的优缺点对比,如表1所示。

3f32_503b386b1f62f.jpg

表1 各测试工具优缺点比较

根据现有经验,我们曾尝试了表1中四种单元测试方法。很难说哪一个方案是最好的,在目前的项目实践中,我们联合应用Robolectric和Java JUnit,为了避免Robolectric速度、模拟功能不全和质量检测工具等问题,需要对Robolectric的代码进行修改,并尽量减少对其的应 用。转而通过一些结构上的应用,大量采用Java JUnit测试。

JUnit。鼎鼎大名的Java测试框架,无数应运而生的mock框架支持,使其无论是可用性还是易用性方面在Java领域无人能及。利用JUnit可以实现非常快捷单元测试。也是最常见的一种单元测试形式。

Robolectric。这是由Pivotal Labs开发的一套开源的Android单元测试框架。其通过一系列对底层Android元素的替换来实现对原有元素调用的模拟,从而实现脱离模拟器的测 试。非常值得一提的是,在测试服务器请求时,Robolectric的数据模拟和延时发送模拟,给多线程状态下的测试提供了很好的解决方法。

Robotium。 因为其对整体应用的黑盒操作特性,绝大多数技术文章将其作为功能测试工具,因此后文在叙述功能测试时也有提及。但因为其已有代码库,进行测试前需要组合编 译,而且可以完成方法级别的功能测试,因此本文还是将其描述重点在单元测试时和其他工具进行对比说明。但并不等于它就是单元测试。

Android JUnit。这是一种最常见的单元级别测试。它由Android官方提供,通过虚拟机自身提供的测试接口完成。图3源于Android开发者官网,基本上 阐述了整个测试框架各个组成部分。其中,最下面方框中描述的即为框架中基于JUnit的测试部分。可以看到,其通过Android的内部测试包,调用测试 执行模块完成对目标应用的测试。

该测试最大的好处是其与Android系统结合紧密,贴近真实环境。但其弊端也正是因为使用大量基于平台的虚拟,导致测试运行速度相对偏慢,影响测试效率。又因为开发过程中,单元测试是最大,也是最常规的测试,所以这种影响带来的效率降低就显得特别严重。

ebf7_5049558cb74a5.jpg

图3 Android JUnit测试框架

小结

本文我们介绍了移动开发中的常见问题、技术解决方案的基本思路,以及在具体实现中所要涉及的结构化组件和单元测试工作。在下期《程序员》中,我将继续讲解技术方案的具体实现方法,包括如何通过框架选取实现测试驱动方案,业务行为驱动的功能测试方案、持续集成、部署,以及如何让调试可持续化。

本文延续上期话题,深入到测试、持续集成和部署等环节,紧密结合移动开发方法和技术,围绕Android平台的开发讨论提供更高质量移动产品的解决方案。

通过清晰的架构实现测试驱动

通过《程序员》杂志9月刊文章的分析,我们可以看到,每一种工具都很难从完全意义上解决工程当中追求快速和高质量的要求。那么就需要通过整体架构实践,更好地解决这方面的问题。以下两种结构方法可供参考。

平台和领域的分层结构

如图1所示,这是一种最基础的分层结构。它将和Android平台相关的内容都包裹在了平台层,而将领域、状态、逻辑等和平台无关的内容完全隔离开来。创建项目时,将平台层和测试层分别对领域层产生依赖,以这样的方式达成对项目和对测试的独立构建。

这样做的好处是,领域层可以通过Java的JUnit进行完全测试,而项目各个类之间的因为有明显的项目级别分层,使得代码的考量更加清晰,方便于检验最核心关键的业务逻辑。且测试速度非常快,便于快速迭代。

但其带来的不便之处就是,随着项目代码的日益复杂,其与Android内部结合就越紧密,这时往往越难将业务逻辑很清晰的剥离。部分的业务逻辑将被分片散落在一些平台相关的调用当中。因此我们认为这样的一种层次逻辑更多地适用于简单的项目之中。

3203_5061286bc38e9.jpg

图1 平台和领域的分层结构

MVP(Passive View)架构

许多文章对Passive View是属于MVP还是MVC有各种不同角度的争论。这里我并不想过多地在词语上做过多纠缠,主要是希望通过描述这样的一种结构来树立比较好的对于Android开发的架构模型。

具体到Passive View的实现,如图2所示,描述了一个基本的原理。

随着项目的不断扩大复杂化,我们需要更加清晰化的代码架构。所以,Passive View对平台和领域的分层结构的层次结构有了更深层次的改进。引入Passive View模式的意义实际上还是从测试出发。出于对JUnit快速性能的青睐,所以依然尽量把层次划分为依赖Android内核的部分和非依赖部分。对于前 半部分,可以用基于Roboletric的上层测试完成,相对应的后半部分则可以使用标准Java进行单元测试。这样做既加快了测试速度,又得以保障测试的覆盖率。

baca_5061290a0cd3f.jpg

图2 Passive View架构实现原理图

更多详细的架构资料,请大家参考《GUI Architecture》一文,相信会得到许多很好的想法。

测试驱动开发的实现

之所以要强调代码框架结构,最重要的原因就是寻找快捷方便的途径进行TDD开发。在上一篇文章中已提到了Android常见的集中单元测试工具。之所以将框 架设计方式引入测试驱动开发过程,目的是将应用代码分开处理、分而治之。最大限度让各工具间扬长避短。最终实现高效率测试驱动的目的。

事实上,在目前的开发领域,我们也看到了许多正在应运而生的开发框架,例如Android Spring框架。这些都是下一步需要努力和完善的目标。

业务行为驱动的功能测试方案

如果说单元测试驱动开发帮助我们从开发角度完成了对代码质量的控制,那么基于业务行为的功能测试则为从业务到实现的统一、软件质量的保障提供了重要的解决方法。

功能(验收)测试:就功能测试而言,所指基本上就是测试科目中常提到的黑盒测试。只不过这里加上了更多具有上下文的信息,使得一次完整的黑盒测试更具有实质上的功能意义。

在 Android的开发中,通常是模拟真机或模拟器的用户操作(例如点击或滑动),来检测操作的结果是否符合预期。这个过程可以很好地代替人工的操作,更快 速和大量完成重复性的测试工作,特别是在发展较快、平台和系统版本覆盖较广的项目中,可以起到节约人力成本、提高测试覆盖与准确性的作用。

在常用的工具中,可以选取上一篇文章中介绍过的Robotium或Native Driver来实现。

前者社区发展速度快,实现功能相对更加完善,例如实现了一些手势操作效果等。不过问题是Robotium的组织目前正在倾向闭源化,有些最好的新功能已无法在开源版本中寻找到。

后者的原理是通过植入应用后门的方式,实现对应用的发出指令和进行资源获取。其物理模型比较适合不能再目标设备安装测试应用,或者希望远程控制的情况。开源状况良好,只是近一年,Native Driver的团队把重点发在其他平台上,对Android的更新比较慢。

基于场景的的跨平台验收测试:基于场景的验收测试,好处是可以在业务人员和开发人员之间建立验收机制。通过一系列关于场景的自然语言描述,完成测试的原始编 码。Cucumber是一个在行为驱动开发(BDD)领域比较常见的工具。其基本方法是通过执行文字形功能描述语言来实现对软件的自动化测试。图3展示了 一个常见的Cucumber测试场景。在Android开发中,通常是解析Cucumber,根据内容分情况拆分正具体的操作步骤。将这些步骤用基于 NativeDriver的Java代码进行实现,通过NativeDriver从指令端到设备端的Android自动测试框架完成控制与校验的自动化测 试。

84dc_50612a3536eaf.jpg

图3 常见的Cucumber测试场景

当然,这些步骤也可以通过Robotium的远程控制(RC)调用来实现。其原理类似,如图4所示。

该方案还有额外的好处—用同样的方法,通过Cucumber可以实现对UIAutomation等其他平台自动化测试工具的控制。实现一份用例,多个平台的测试解决方案。图5给出了一个iOS平台上的基于Cucumber的跨平台测试实例。

fa5f_50612a618a4e3.jpg

图4 Cucumber测试实例

e669_50612aa72955d.jpg

图5 iOS平台上基于Cucumber的跨平台测试实例

从持续集成到部署

Jenkins最基本的持续集成

在做好了各种测试实践后,需要考虑如何保证这种实践在每一次提交都产生效果,并且提供对代码库的不断保护。这里引入常用敏捷实践中持续集成的概念。

持 续集成主要是为了能够更好为产品在整个开发过程中提供交付保障。相对比传统服务器领域,移动开发中,碰到最多的问题是环境的不同与测试包的相对封闭。以前 通过改一个配置实现服务器实时测试修改的方法,很难直接应用于移动开发。此外,作为整个服务边缘的移动应用,往往会遇到大量不同的测试环境。

所以如图6所描述的,需要在持续集成服务器上部署相关的应用包,完成对不同环境的开发与测试。这样的测试通常是由持续集成服务器引导的不同物理移动设备来完成,以保证最终测试包的可交付性。尤其适用于对于网络和性能等相关的测试。

80f3_50612ae03a67e.jpg

图6 利用相关应用包完成对不同环境的开发与测试

当然,如果细心的话,也可以看出图6中对于产品版本与配置管理的一些端倪。

OTA自动化部署

持续集成帮助我们有了稳定的应用包。有了这些包,我们现在就差最后的一步—自动化部署。在移动的真实交付中,由于安装包需要下载到移动终端完成。所以自动化部署也必须要模拟这一过程完成交付。

这里我们推荐使用持续集成服务器关于邮件服务推送的应用插件来完成。具体的过程通常为,在完成编译并顺利通过测试后,持续集成服务器会根据制定终端列表,推送测试内容以供安装。推送者收到请求后,可以根据需要自行安装相应apk文件,达到部署效果。

这样做打通了移动开发最后一步的障碍。并有效沟通了管理、设计、业务与测试的各个部门人员。持续集成管理员还可以通过管理安装邮件列表的形式,自行选择不同版本,环境安装包对不同相关人员的推送。

让调试可持续化

有 了开发,有了一系列持续化集成作业,有了作业完成的自动化打包部署,貌似可以休息了。但正如DevOps概念所说,虽然做了许多努力,但我们依然承认会有 错误的出现,那么如何尽早发现错误并准确定位,最终完成就显得尤为重要。在不同阶段,我们尝试使用不同的方法来进行调试。下面介绍我们的两个实践方法。

开发后调试。旧有的logcat是一个很好的调试工具,它在开发中起到了重要的作用,但对于做探索测试的QA们而言,大量繁琐的Debug信息往往令人看得眼花缭乱。

这 时我们就需要一个更好的工具进行错误栈的准确定位,因此我们引入了Acra。这是一个开源工具包,其功能是自动化地将Android应用的错误报告发送到 GoogleDoc或着Email等的可记录文本中。它的目的是为了帮助Android应用开发者在错误发生时收集行为和技术数据。

上线后的持续关注当然在上线后,Google Play也为我们提供了一个非常有好的平台用以收集各种来自用户的反馈信息。其中包括下载量、评价、应用异常报告等。

2480_50612b2c496ca.jpg

769e_50612b2d5d71a.jpg

8754_50612b35d1eac.jpg

图7 移动循环开发流程

在 应用异常报告中,详细记录了整个错误堆栈的信息,更包括错误信息的总数量、周发生次数,以及版本时间等信息。因为Android平台设备性能、具体型号等 多方面内容,并不一定所有的错误信息都一定去进行处理,但这个平台提供了一个持续关注上线情况的基础,为产品的紧急处理、故障修复和在开发提供了重要的信 息来源。

这里还要强调,测试优先的TDD实践,在每一个错误修复前,都应该把测试补好,这是同样错误不会再次出现的最重要保障。

总结

本文提出了移动开发过程中常见的问题,并分析了基于开发与维护过程中的一些具体实践方法,尝试从移动应用的开发技术角度提供解决方案。

除此之外,事实上和常见的软件开发一样,还有诸如配置管理、发布管理等也是必不可少的。我们总结了如图7所示的一个移动开发循环。通过对不同方面的配置技术实现,完成移动的全流程开发,供读者做更深的思考和方法演进。

作者王哲,ThoughtWorks咨询师。致力于将敏捷先进的技术管理经验与移动产品紧密结合。

转载于:https://www.cnblogs.com/cc-Cheng/archive/2012/10/15/2724325.html

相关文章:

C# 格式串(收藏)

一、用{0:?}格式化 可通过 String.Format 方法或通过 Console.Write 方法格式化数值结果,其中后一种方法调用 String.Format。使用格式字符串指定格式。下表包含受支持的标准格式字符串。格式字符串采用的形式为 Axx,其中 A 为“格式说明符”&#xff0…

巧用CSS的Wave滤镜

作者:冯永曜 "wave"滤镜,看它的名称你可能就能想到其效果,正如你想的那样,它的作用是把对象按照垂直的波形样式扭曲,从而产生一种特殊的效果。它共有5个参数:"add":表示是否…

关于vmware虚拟机linux的扩容问题

Linux的VM虚拟机扩展磁盘空间 (1)vmware软件中编辑虚拟机设置中又扩容的选项,这里不做介绍。 (2)启动VM环境下的linux操作系统,添加新分区,需要root账号身份。 3.1 【fdisk -l】 extend 对应的是sda4&#…

用Python玩转PPT!

作者 | 陈熹来源 | 早起Python今天本文将基于第三方库pptx,详细讲解如何使用Python操作Office全家桶最后一位——PPT。安装pptx是一个非标准库,需要在命令行中安装pip install python-pptx要注意,安装的时候是python-pptx,而实际调…

贝塞尔曲线学习

贝塞尔曲线是UIkit中的一个关于图形绘制的类 贝塞尔曲线可以绘制矩形,圆形,直线,曲线,以及它们的混合图形。 系统常用的内置方法 // 创建基本路径 (instancetype)bezierPath; // 创建矩形路径 (instancetype)bezierPathWithRect…

巧用CSS的 Mask 滤镜

作者:冯永曜在网页制作中使用CSS,这已是众所周知,而关于CSS滤镜使用的却介绍得不多。其实,0CSS的滤镜在Dreamweaver3中用起来也很方便,且能使文字产生一种类似图象的效果,但比起图片来可就瘦小多了。不信&a…

Google Analytics功能篇 - 如何跟踪邮件打开率与点击率

有些朋友总会问我,在作邮件营销时,应该如何来跟踪这些流量呢?以便能知道发送的成功率,打开率,点击邮件中的链接数量,怎么实现这样的功能呢? 另外,有一个做邮件群发的朋友给我说&…

Google排名第一的技术,引数十万人关注!网友:差点我就放弃了!

毋庸置疑,Python越来越被认可为程序员新时代的风口语言。无论是刚入门的程序员,还是年薪百万的 BATJ 的大牛都无可否认:Python的应用能力是成为一名码农大神的必要项。 所以,很多程序员把Python当做第一语言来学习。 但对于Python…

python的zip函数

zip()函数 它是Python的内建函数&#xff0c;(与序列有关的内建函数有&#xff1a;sorted()、reversed()、enumerate()、zip()),其中sorted()和zip()返回一个序列(列表)对象&#xff0c;reversed()、enumerate()返回一个迭代器(类似序列) 1 >>> type(sorted(s)) 2 <…

Nginx 搭建负载均衡

1.其实我这里并不是访问量很大&#xff0c;主要用于版本升级和维护而搭建的 2.忽略nginx安装和jetty的安装配置&#xff0c;我是在一台Linux服务器上装了两个jetty服务&#xff0c;部署两套jetty服务很简单&#xff0c;其实改改jetty.sh 脚本即可 JETTY_HOME/opt/jetty2/ JETT…

巧用CSS的Glow滤镜

作者&#xff1a;冯永曜对一个对象使用“glow”滤镜后&#xff0c;这个对象的边缘就会产生类似发光的效果&#xff0c;这种效果在PHTOSHOP中做起来都比较麻烦&#xff0c;而在DW3中用CSS的“glow”滤镜来制作却是如此地简单&#xff0c;而且节约不少字节。“glow”滤镜只有两个…

10大经典排序算法,20+张图就搞定

作者 | 李肖遥来源 | 技术让梦想更伟大冒泡排序简介冒泡排序是因为越小的元素会经由交换以升序或降序的方式慢慢浮到数列的顶端&#xff0c;就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样&#xff0c;故名冒泡排序。复杂度与稳定性思路原理以顺序为例从第一个元素开始一…

C# MoreLinq 扩展安装

为什么80%的码农都做不了架构师&#xff1f;>>> http://blog.csdn.net/lee576/article/details/42716905 MoreLinq是一个对Linq to object的扩展类库,它是一个开源项目(http://code.google.com/p/morelinq/source/browse 天朝已对google全力封禁,所以要翻墙)&#…

IOS学习博客不错的大部分是原创

http://blog.csdn.net/iukey/article/category/955062

巧用CSS的Light滤镜

作者&#xff1a; 冯永曜Light滤镜能产生一个模拟光源的效果&#xff0c;但使用它要通过调用它的“方法&#xff08;Method&#xff09;”来实现&#xff0c;这就要用到一些Javascrpt知识&#xff0c;虽然有一点难度&#xff0c;但产生的效果也是奇特的&#xff0c;你看看下面的…

没有场景,不做单点技术输出,360数科如何做金融科技的最佳实践?

作者 | Just 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 从互联网金融公司转变为金融科技公司&#xff0c;品牌升级后的360数科强化了“科技”的外衣。 在近期的首个360数科技术开放日&#xff0c;360数科CEO吴海生表示&#xff0c;他们已经做好金融科技的最佳…

react构建淘票票webapp,及react与vue的简单比较。

前言 前段时间使用vue2.0构建了淘票票页面&#xff0c;并写了一篇相关文章vue2.0构建淘票票webapp&#xff0c;得到了很多童鞋的支持&#xff0c;因此这些天又使用react重构了下这个项目&#xff0c;目的无他&#xff0c;只为了学习和共同进步&#xff01; 项目技术栈 前端技术…

【机器学习】机器学习算法优缺点对比(汇总篇)

作者 | 杜博亚来源 | 阿泽的学习笔记「本文的目的&#xff0c;是务实、简洁地盘点一番当前机器学习算法」。文中内容结合了个人在查阅资料过程中收集到的前人总结&#xff0c;同时添加了部分自身总结&#xff0c;在这里&#xff0c;依据实际使用中的经验&#xff0c;将对此模型…

PLSQL developer 连接不上64位Oracle 解决办法

在64位Windows2003上安装Oracle后&#xff0c;用PLSQL developer去连接数据库出现报错&#xff1a; Could not load "……\bin\oci.dll" OCIDLL forced to…… LoadLibrary&#xff08;……oci.dll&#xff09; returned 0 原因&#xff1a; oci.dll是64位的&#xf…

Docker 使用教程

概括  Docker与传统虚拟机的区别 与传统虚拟机的区别  Docker的安装 的安装  Docker daemon &#xff0c; client &#xff0c; containerd  镜像与容器操作  容器运行配置  Docker网络配置 网络配置  Alpine Docker Image  制作自己的 Docker Image …

话说CSS滤镜

作者&#xff1a;http://www.swtv.com.cn/adjunct/nr/css/css.htmAlpha 透明层次&#xff1a;滤镜效果语法&#xff1a;STYLE"filter:filtername(parameter1,parameter2,parameter3...)"其中&#xff1a;filtername为滤镜的名称&#xff1b;parameter1,parameter2等为…

面向隐私AI的TensorFlow深度定制化实践

作者 | Rosetta团队出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;之前我们整体上介绍了基于深度学习框架开发隐私 AI 框架中的工程挑战和可行解决方案。在这一篇文章中&#xff0c;我们进一步结合 Rosetta 介绍如何定制化改造 TensorFlow 中前后端相关组件&#xf…

”拿来搞笑“的大学生活

”拿来搞笑“这词&#xff0c;是我舍友对我说过好几遍&#xff0c;我才觉得这词用来形容我大学的生活再恰当不过了&#xff0c;感谢他送给我这个词。 下面就列一下我大学期间”拿来搞笑“的事情&#xff1a; —&#xff1a;无偿捐血400毫升。当时认为是一件微不足道的事情&…

巧用CSS的Border属性

。作者&#xff1a;冯永曜 来源&#xff1a;黄山村夫 制作过网页的人都有为画线而烦恼的经历&#xff0c;本文介绍的小技巧也许对你有所帮助。我们先来认识一下“Border”&#xff08;画边框&#xff09;&#xff0c;它是CSS的一个属性&#xff0c;用它可以给能确定范围的HTML标…

阿里资深算法专家:如何突围大厂算法面试?

2020 届秋招&#xff0c;算法岗灰飞烟灭。最聪明的应届生 / 程序员 &#xff0c;都在极度竞争中&#xff0c;面临着前所未有的激烈 PK 。学生因“内卷”而迷茫&#xff1b;初级程序员遇职业发展瓶颈而困惑...面对重重压力&#xff0c;苦不堪言。to do list 上写满计划&#xff…

乡下人最嘲笑城里人的16件事,无语了!

一、出门「taxi」&#xff0c;乘电梯上七楼的健身房&#xff0c;然后在跑步机上挥汗如雨。 二、半夜上网&#xff0c;去歌厅、舞厅&#xff0c;困了不睡觉。之后失眠&#xff0c;再吃安眠药。 三、管儿子叫「小兔崽子」&#xff0c;管宠物狗叫儿子。 四、挑最有特色的饭店吃…

2017浅谈面试(一)

2017给自己一个目标&#xff0c;制定一份计划&#xff0c;新的开始&#xff0c;跟随创业团队风险无处不在&#xff0c;不过还是要选好Boss。 2016一个煎熬&#xff0c;悲剧&#xff0c;没发工资的日子&#xff0c;一等就等了5个月&#xff0c;零散的就拿到了一个半月工资&#…

乘风破浪的PTM:两年来预训练模型的技术进展

作者 | 张俊林来源 | 深度学习前沿笔记专栏Bert模型自18年10月推出&#xff0c;到目前为止快两年了。它卜一问世即引起轰动&#xff0c;之后&#xff0c;各种改进版本的预训练模型&#xff08;Pre-Training Model, PTM&#xff09;与应用如过江之鲫&#xff0c;层出不穷。Bert及…

DW中CSS属性详解

作者&#xff1a;未知 来源&#xff1a;5D多媒体 在Dreamweaver的CSS样式里包含了W3C规范定义的所有CSS1的属性&#xff0c;Dreamweaver把这些属性分为Type&#xff08;类型&#xff09;、Background&#xff08;背景&#xff09;、Block&#xff08;块&#xff09;、Box&a…

第十周项目5:贪心的富翁

上机内容&#xff1a;用循环语句完成累加 上机目的&#xff1a;学会循环语句的使用 /* * Copyright (c) 2012, 烟台大学计算机学院 * All rights reserved. * 作 者&#xff1a;孙锐 * 完成日期&#xff1a;2012 年 10 月 31 日 * 版 本 号&…