June 21, 2011 | Tommy Maintz
The scalability, maintainability and flexibility of an application is mostly determined by the quality of the application’s architecture. Unfortunately, it’s often treated as an afterthought. Proofs of concept and prototypes turn into massive applications, and example code is copied and pasted into the foundations of many applications. You may be tempted to do this because of the quick progress that you see at the start of a project.
一个应用程序的可伸缩性、可维护性和灵活性主要取决于应用程序的架构质量。不辛的是,这经常被当做一种事后才考虑的东西。仅仅是概念和原型就变成了大规模应用程序,并且样例代码被复制和粘贴到许多应用程序的基础之中。因为在项目开始时有快速的进度, 你也许打算这么做。
However, the time saved will be relatively low compared to the time spent on having to maintain, scale and often refactor your application later in the project. One way to better prepare for writing a solid architecture is to follow certain conventions and define application views, models, stores and controllers before actually implementing them. In this article, we’ll take a look at a popular application and discuss how we might architect the user interface to create a solid foundation.
不管怎样,节省出来的时间相对低于花费的时间——后期项目你不得不维护、伸缩和经常重构你的应用。写一个可靠架构有一条更好的解决之道,就是跟随确定的惯例,在实际实现之前就定义好应用的视图、模型、存储和控制器。在此文中,我们将看到一个流行的应用,并且讨论如何通过构建用户界面来创造一个可靠的基础。
Code Organization 代码组织
Application architecture is as much about providing structure and consistency as it is about actual classes and framework code. Building a good architecture unlocks a number of important benefits:
应用架构就很大程度上是关于提供结构和一致性,好比它是关于实际的类和框架代码。搭建一个良好的架构如下若干好处:
- Every application works the same way so you only have to learn it once
- It’s easy to share code between apps because they all work the same way
- You can use Ext JS build tools to create optimized versions of your applications for production use
- 每个应用都以同一种方式工作,如此一来,你只需要了解它一次。
- 不同应用中之间易于分享代码,因为它们都以同一种方式工作。
- 为了在生产中使用,你可以用Ext JS build toosl来创建优化过的应用程序版本。
In Ext JS 4, we have defined conventions that you should consider following when building your applications — most notably a unified directory structure. This simple structure places all classes into the app folder, which in turn contains sub-folders to namespace your models, views, controllers and stores.
在 Ext JS 4中,我们已经定义了在你创建应用程序时,应该考虑遵守的惯例——最显著的是一个统一的目录结构。这个简单的结构把所有的类放置在app文件夹——反过来,它又包含了子目录,根据你的模型、视图、控制器和存储建立命名空间。
While Ext JS 4 offers best practices on how to structure your application, there’s room to modify our suggested conventions for naming your files and classes. For example, you might decide that in your project you want to add a suffix to your controllers with “Controller,” e.g. “Users” becomes “UsersController.” In this case, remember to always add a suffix to both the controller file and class. The important thing is that you define these conventions before you start writing your application and consistently follow them. Finally, while you can call your classes whatever you want, we strongly suggest following our convention for the names and structure of folders (controller, model, store, view). This will ensure that you get an optimized build using our SDKTools beta.
Ext JS 4提供了如何构造你的应用程序的最佳实践,还有余地来调整我们建议的命名文件和类的惯例。对于此例,你可以在你的项目中决定,想要添加一个“Controller”后缀到你的控制器,比如“Users”变成了“UsersController”。在这个情况下,记住,控制器文件和类,都要始终添加一个后缀。重要的是,在开始写你的应用之前,就定义这些惯例,并且一直遵守它们。最终,当你可以调用你用任何想要的类时,我们强烈建议遵守我们的命名和目录结构(控制器、模型、存储、视图)惯例。这将确保你使用我们的SDKTools beta 能得到一个优化过的发布版本。
Striking a Balance 发现平衡
Views 视图
Splitting up the application’s UI into views is a good place to start. Often, you are provided with wireframes and UI mockups created by designers. Imagine we are asked to rebuild the (very attractive) Pandora application using Ext JS, and are given the following mockup by our UI Designer.
把应用UI分割到视图是个好的开始。通常,你会被提供有wireframes和设计师创建的UI mockups。设想一下,我们被要求使用Ext JS来重建(非常诱人的)Pandora应用,并且我们的UI设计师已经提供了要遵守的 mockup。
What we want to achieve is a balance between the views being too granular and too generic. Let’s start by seeing what happens if we divide our UI into too many views.
我们想要的是,在视图变得太粒化和太泛化之间,达成一个平衡。让我们瞧瞧如果把UI分割成过多的视图,会发生些什么。
Splitting up the UI into too many small views will make it difficult to manage, reference and control the views in our controllers. Also, since every view will be in its own file, creating too many views might make it hard to locate the view file where a piece of the UI or view logic is defined.
On the other hand, we don’t want our views to be too generic because it will impact our flexibility to change things.
把UI分割成过多小视图,会使我们在控制器中难以管理、引用和控制视图。同样,因为每个视图会在它自己的文件中,创建过多的视图会使我们难以定位,定义了UI块或视图逻辑的视图文件。
另一方面,我们不想视图太泛化——因为这将影响我们改变事物的灵活性。
In this scenario, each one of our views has been overly simplified. When several parts of a view require custom view-logic, the view class will end up having too many responsibilities, resulting in the view class becoming harder to maintain. In addition, when the designers change their mind about the arrangement of the UI, we will end up having to refactor our view definition and view logic; which can get tedious.
The right balance is achieved when we can easily rearrange the views on the page without having to refactor them every time. For example, we want to make the Ad a separate view, so we can easily move it around or even remove it later.
在这个场景中,我们的每个视图已经过于简化。当一个视图的若干部分都需要自定义的视图逻辑,视图类将告终,因为它包含了过多的责任,导致视图类变得难以维护。此外,当设计师改变了他们关于UI排列的想法, 我们也将告终,因为不得不重构我们的视图定义和视图逻辑——这会变更乏味要命。
当恰当的平衡达成时,不必每次重构它们,我们就可以简单排列页面上的视图。比如,我们想要广告一个单独的视图,我们能简单的在周围移动它,甚至是在往后删除它。
In this version, we’ve separated our UI by the roles of each view. Once you have a general idea of the views that will make up your UI, you can still tweak the granularity when you’re actually implementing them. Sometimes you may find that two views should really become one, or a view is too generic and should be split into multiple views, but it helps to start out with a good base. I think we’ve done that here.
在这个版本中,我们已经通过每个视图的角色分离了UI。一旦你有了一个将能组成UI的,关于视图的整体思路——当你实际实现它们时,你仍能调整粒度。有时,你可能发现,两个视图确实应该合并成一个,或者一个视图太泛化并且应该分割成多个视图,但是它有助于打下一个良好的基础。我相信我们已经在此完成了这个目标。
Models 模型
Now that we have the basic structure of our views in place, it’s time to look at the models. By looking at the types of dynamic data in our UI, we can get an idea of the different models needed for our application.
现在,我们已经有了视图放在恰当位置的基础结构。是时候看看模型了。通过观察我们UI中的动态数据类型,我们可以得到应用中需要的不同模型的主意。
We’ve decided to use only two models — Song and Station. We could have defined two more models called Artist and Album. However, just as with views, we don’t want to be too granular when defining our models. In this case, we don’t have to separate artist and album information because the app doesn’t allow the user to select a specific song by a given artist. Instead, the data is organized by station, the song is the center point, and the artist and album are properties of the song. That means we’re able to combine the song, artist and album data into one model. This greatly simplifies the data side of our app. It also simplifies the API that we have to implement on the server-side because we don’t have to load individual artists or albums. To summarize, for this example, we’ll only have two models — Song and Station.
我们已决定仅仅使用两个模型——“歌曲(Song)”和“电台(Station)”。我们可以定义两个模型名叫“艺人(Artist)”和“唱片(Album)”。尽管如此,就像和视图一样,我们不想当定义模型时太粒化了。在此例中,我们不想分离艺人和唱片的信息,因为这个应用不允许用户通过一个给定的艺人选择特定的歌曲。相反,数据是通过电台维护的,歌曲是中心点,艺人和唱片是歌曲的属性。这意味着我们能够组合歌曲、艺人和唱片的数据到一个模型。这极大地简化了我们应用的数据层。这也简化了我们必须在服务器端实现的API, 因为我们不想加载独立的艺人和唱片。总结,此例中,我们只需两个模型:歌曲和电台。
Stores 存储
Now that we’ve thought about the models our application will use, lets do the same for stores.
现在,我们已经想好了应用中使用的模型,同样想想存储。
Figuring out the different stores you need is often relatively easy. A good strategy is to determine all the data bound components on the page. In this case, we have a list with all of the user’s favorite stations, a scroller with the recently played songs, and a search field that will display search results. Each of these views will need to be bound to stores.
理解你所需要的各种存储通常相对简单。一个好的策略是确定页面上所有的数据绑定组件。在此例中,我们有一个带有用户喜好电台的列表,一个带有最近播放过的歌曲的滑动组件,还有一个显示搜索结果的搜索域。这些视图每个都将需要绑定到存储。
Controllers 控制器
There are several ways you can distribute the application’s responsibilities across your application’s controllers. Let’s start by thinking about the different controllers we need in this example.
你有几种方式通过控制器来分发应用的职责。让我们想想这个例子中需要的各种控制器。
Here we have two basic controllers — a SongController and a StationController. Ext JS 4 allows you to have one controller that can control several views at the same time. Our StationController will handle the logic for both creating new stations as well as loading the user’s favorite stations into the StationsList view. The SongController will take care of managing the SongInfo view and RecentSong store as well as the user’s actions of liking, disliking, pausing and skipping songs. Controllers can interact with each other by firing and listening for application events. While we could have created additional Controllers, one for managing playback and another for searching stations, I think we’ve found a good separation of responsibilities.
这里我们有两个基本的控制器——SongController和StationController。Ext JS 4允许你使用一个控制器控制同时多个视图。我们的StationController将处理创建新的电台和加载用户喜好电台到StationList视图的逻辑。SongController将关注于管理SongInfo视图、RecentSong存储和用户行为——诸如喜欢、不喜欢、暂停和跳过歌曲。控制器可以通过触发和监听事件,互相进行交互。当我们创建了额外的控制器时——一个为了管理回播,一个为了搜索电台——我想,我们已经发现一个良好的职责分离。
Measure Twice, Cut Once 三思而后行
I hope that sharing our thoughts on the importance of planning your application architecture prior to writing code was helpful. We find that talking through the details of the application helps you to build a much more flexible and maintainable architecture.
我希望在此分享的,关于制订应用架构的计划先于编写代码的重要性的想法,是有益的。我们发现,从头到尾谈论这个应用的细节,能够帮助你构建一个更灵活、更可维护的架构。
Written by Tommy Maintz
Tommy Maintz leads the development of Sencha Touch. With extensive knowledge of Object Oriented JavaScript and mobile browser idiosyncracies, he pushes the boundaries of what is possible within mobile browsers. Tommy brings a unique view point and an ambitious philosophy to creating engaging user interfaces. His attention to detail drives his desire to make the perfect framework for developers to enjoy.