Prerequisite knowledge
Knowledge of Flex is required.
 
User level
Intermediate
Required products
Flash Builder (Download trial)
 
As a software engineer joining a new project, I want to be able to get the code quickly, build it, and then run the application. I don't want to have to work through a complex set up procedure, read countless how-to documents, or learn the detailed ins-and-outs of the application to simply get started.
 
In addition, once the environment is up and running, I want to always be able to:
 
  • Commit all modified files, even project configuration files (for example, .project, .actionScriptProperties, and .flexProperties files) without breaking anyone else's environment.
  • Check out all incoming files and be completely synchronized with the repository without having to reconfigure the local environment or check out files selectively.
When working with Flash Builder—and Eclipse in general—this simple task can become challenging. In this tutorial you will find lots of tips to help you and your team configure your projects for maximum efficiency, reduce set up and maintenance costs, and get new developers up and running quickly.
 

 
Avoid hardcoded paths in configuration files

One common source of problems is absolute paths in project configuration files. There are several ways to inadvertently create an absolute path reference. Typically when you create linked folders an absolute path reference is added to the .project configuration file; for example:
 
<linkedResources> <link> <name>linkedFolder</name> <type>2</type> <location>/Users/youUser/path/to/hardcoded/folder</location> </link> </linkedResources>
Absolute paths are also commonly hardcoded when you link a SWC library stored outside the project or workspace folder hierarchy. In this case the .actionScriptProperties file will hold a reference; for example:
 
<libraryPathEntry kind="3" linkType="1" path="/Users/youUser/path/to/hardcoded/lib.swc" useDefaultLinkType="false"/>
 
Use linked resources
So how can you avoid hardcoded paths? The answer is to use linked resources. A linked resource is nothing more than a path variable stored at the Eclipse workspace level. You can define your custom variables by choosing Window > Preferences > General > Workspace > Linked Resources. If you define a CUSTOM_PATH variable there, then you can use it in the project configuration files; for example:
 
<linkedResources> <link> <name>linkedFolder</name> <type>2</type> <location>CUSTOM_PATH/folder</location> </link> </linkedResources> <libraryPathEntry kind="3" linkType="1" path="${CUSTOM_PATH}/lib.swc" useDefaultLinkType="false"/>
Note that the syntax is slightly different in .project and .actionScriptProperties files. In the former, you reference the path variable using its only name ( CUSTOM_PATH ) whereas in the latter you also need a dollar sign and curly bracket symbols ( ${CUSTOM_PATH} ).
 
 
Use ${flexlib} to link framework libraries
There are cases where you might want to link one or more Flex SDK libraries entirely into your project. This is typically the case when working with automation libraries in which case you have to include automation.swc, automation_dmv.swc, and automation_agent.swc. These SWCs, along with others, are normally in the libs folder of the Flex SDK used in your project. To include and link them in your project you'd normally add the following statement in the Additional Compiler Arguments settings:
 
-include-libraries /path/to/SDK3.0/libs/automation.swc /path/to/SDK3.0/libs/automation_dmv.swc /path/to/SDK3.0/libs/automation_agent.swc
As you can see, the path to the SDK is again hardcoded. This is not portable across developer environments. Plus, it's likely that if you switch to a different SDK version these linked libraries won't be updated accordingly, creating random conflicts and behaviors. A possible solution here is to use the special ${flexlib} token, which will always point to the SDK folder configured for the project. If you change the SDK for the project or your workspace you can be sure it will be updated accordingly. You can then use:
 
-include-libraries ${flexlib}/libs/automation.swc ${flexlib}/libs/automation_dmv.swc ${flexlib}/libs/automation_agent.swc
 
Link your bin folder to a network folder
There is a nice approach when your application needs to target multiple environments. You can define a linked resource for the build directory and specify a shared network drive. This path is then symbolically linked into your application servers for all the different environments (development, testing, pre-production, production, and so on). This way as soon as you build from your IDE, you can run the app in all these environments. If the service layer team needs to restart a specific environment, you can switch to another one to continue developing. The downside is that the build may be slowed down by copying to a network drive instead of a local disk, but this not significant if a large project is well structured into separate libraries and modules or sub-applications.
 

 
Configure compiler settings

There are several compiler options that you can configure to streamline your Flex 4 development.
 
 
Explicitly specify the SDK version your project uses
Flash Builder allows developers to specify a default SDK version to be used when a project isn't tied to a certain version (Window > Preferences > Flash Builder > Installed Flex SDKs). If a project doesn't specify a specific SDK, then the default one is used. It's fairly common for different developers in the same team to have different SDK versions installed or for two developers to configure a different default SDKs.
 
If your projects are configured to use the default SDK it means that, potentially, different developers will compile the project using different versions of the SDK, often resulting in unexpected behaviors and unpredictable errors that are quite hard to debug and isolate.
 
The likelihood of these problems will be greatly increased if your project has monkey-patched classes of the SDK. Imagine Developer 1 patches ClassA of SDK 3.1. Unaware of this, Developer 2 compiles the project using SDK 3.0. Since ClassA is a monkey-patched class it will be used, but the rest of the framework classes used will be from SDK 3.0. You can experience various runtime errors and undesirable behavior when this occurs. Avoid this situation by explicitly specifying an SDK version: open project properties, select Flex Compiler, and then select Use A Specific SDK.
 
 
Don't link any SDK class in your libraries
Whether you're a library developer or a developer using third-party libraries it's very important to make sure that the libraries you use or produce don't link to any specific SDK class. If this unavoidable, make sure you understand the impact it might have in your project.
 
Imagine you're working on a Flex project using SDK 3.5. To accelerate the development you decide to use a third-party library called badLibrary.swc. This library was created using SDK 3.1 and for some reason different SDK classes were linked in the final SWC using the Merge Into Code option (for example, UIComponent and its dependencies). When you use badLibrary.swc in your project, due to compilation precedence, all classes found in the SWC files in the classpath will be used instead of the ones from the selected Flex SDK. This means that your project will be compiled using the UIComponent class from SDK 3.1 (distributed with badLibrary.swc) instead of the one from SDK 3.5. This can cause all sorts of random and strange behaviors.
 
If you're an application developer and you want to use a third-party library you can inspect its contents using Flash Builder to find out if it's linking to any specific SDK classes. In the example shown in Figure 1, MyComponent.as is a component inheriting from UIComponent. In the library project properties the Merge Into Code option has been selected as the framework linkage type. This means that any required SDK class will be copied to the resulting SWC. MyProject is using the produced badLibrary.swc file. As you can see in the Referenced Libraries, node several classes on the mx.* package are referenced and will be used instead the ones from the SDK. It is important to avoid using libraries including any bits or pieces of the SDK unless it's justified. If you're a library developer make sure, when possible, to use External as the Framework linkage type before distributing your libraries.
 
Figure 1. Linked SDK classes in library.
Figure 1. Linked SDK classes in library.
 
Use -load-config
In a big project it is very common to use several extra compiler parameters. When you use conditional compilation, functional testing, custom metadata tags (as most modern application frameworks do), and internationalization parameters your additional parameters can end up looking like something like this:
 
-locale en_US -include-libraries ${flexlib}/libs/automation.swc ${flex_lib}/libs/automation_dmv.swc ${flexlib}/libs/automation_agent.swc ${RIA_TEST}/RIATestAgent.swc -define=CONFIG::debugging,true -define=CONFIG::formsRefactor,false -keep-as3-metadata=ArrayElementType,Translate,Translator,ManagedEvents,Answer,AnswersGroup
There are several drawbacks to having all these additional compiler settings:
 
  • The UI provided by Flash Builder to read, modify, and manage these parameters is not designed for large amounts of data. Finding and editing something in this long string can difficult and error prone.
  • These parameters will be stored in the .actionScriptProperties file. Since it's not structured information it can be very tricky to identify and merge any changes with your version control system.
  • If you change something (for example, by adding a new metadata tag to be kept) it's likely that your Continuous Integration environment will get unsynchronized, since it might be using a different configuration source and running the build with Ant or Maven.
A way to avoid this situation is to use the -load-config argument to pass a reference to a compiler configuration file. For example:
 
-load-config+=additionalCompilerParameters.xml
In this example, additionalCompilerParameters.xml would contain something like the following:
 
<?xml version="1.0"?> <flex-config> <compiler> <include-libraries> <library>${flexlib}/libs/datavisualization.swc</library> <library>${flexlib}/libs/flash-integration.swc</library> </include-libraries> <keep-as3-metadata> <name>ArrayElementType</name> <name>Translate</name> <name>Translator</name> <name>ManagedEvents</name> <name>Answer</name> <name>AnswersGroup</name> </keep-as3-metadata> <define> <name>CONFIG::debugging</name> <value>true</value> </define> <define> <name>CONFIG::formsRefactor</name> <value>false</value> </define> </compiler> </flex-config>
If you have problems finding the correct XML syntax for a certain compiler parameter you can add the parameters as an additional compiler setting along with the -dump-config=config.xml option. This will generate a compiler configuration file that includes all the parameters specified. You can then use this generated file as a reference. Another way to learn the syntax for this file is by using SDK/frameworks/flex-config.xml as a reference.
 
Keeping all your compiler settings in an external XML file is also a good way to ensure your Continuous Integration environment is always kept in sync, as well as avoid having to maintain large separate Ant tasks. You can have a simple Ant task pointing to this compiler configuration XML file.
 
 
Include all classes from all source paths in Library projects
In Flash Builder 4, select Include All Classes From All Source Paths for your Library projects. This option is new to Flash Builder 4 and can be found in the project properties, on the Classes tab under the Flex Library Build Properties category. Its biggest advantage is that when a new class is created, moved to another project, or copied elsewhere you do not have to specifically specify that it has to be included in the compiled SWC. How many times have you had to recompile your project because you or someone else forgot to modify or commit the .flexLibProperties file?
 
Some might argue that this option leads you to link unnecessary classes into the SWC file, but it is a best practice to store only those classes that should be compiled into the library inside the library source folder.

 
Use multiple source path folders

There are a number of situations in which using multiple source path folders make sense, including when using monkey-patched classes or during unit testing.
 
Create separate source path folders for monkey-patched classes
Monkey-patched classes and their associated files can be confusing to developers if they are stored in the same source folder as project specific classes. It's a good idea to create a flexSDK source folder and put all patched classes and related resources in there.
 
If you monkey patch the SDK because of some bug, it can also be helpful to create different source folders for each bug patch. For example, you might create a folder named flexSDK-123 (see Figure 2) where 123 is the reported bug number on http://bugs.adobe.com. When you log a bug on Jira and track its progress, it's likely that an official fix will be released at a later stage. Once you get the official fix you'll only have to remove the source folder related to that bug without leaving any unused resource in your project.
 
It's also useful to add a readme.txt file for each patched class explaining the details of the patch. These files are very handy when you upgrade to a new SDK version. Having the details of why the SDK was patched will help you to identify the required changes in the new SDK or, in the case of a bug, it will help you determine if the new SDK version includes a fix.
 
Figure 2. Multiple source path folders for monkey-patched classes.
Figure 2. Multiple source path folders for monkey-patched classes.
 
Create separate source path folders for unit tests and integration tests
To reinforce the separation-of-concerns principle discussed above, it's a best practice to create a separate source path folders for unit tests and your functional testing infrastructure.
 
For example, if you're unit testing my.package.ClassA you'd create my.package.ClassATest. Note that ClassATest is in the same package as ClassA. The difference is that ClassATest would be in the tests source folder whereas ClassA would reside in the default source folder.
 
The same concept applies to instrumentation classes for functional testing. When creating functional tests using the automation APIs, you will probably create some custom automation classes, several classInfo descriptor files, and several functional tests. In this case you can create a folder hierarchy like the one shown in Figure 3.
 
  • The automation subfolder is configured as a source folder and contains instrumentation classes. If you're instrumenting my.package.MyComponent you'll add the corresponding automation class in my.package.MyComponentAutomationImpl in the automation source path folder.
  • The classInfo subfolder contains all the needed automation descriptor files.
  • The tests subfolder is the root folder for your RIATest, QTP, FlexMonkey, and other functional tests.
Sometimes the QA team will want to use a different subset of compiler arguments (for example, to link in automation libraries). An option to handle different subsets of compiler arguments is again using linked resources. You could use a COMPILER_ARGS linked resource like this:
 
-locale en_US -load-config+=${COMPILER_ARGS}
Where COMPILER_ARGS would point to compilerArguments.xml or compilerArgumentsQA.xml
 
Figure 3. Multiple source path folders for unit tests.
Figure 3. Multiple source path folders for unit tests.
Use the {locale} token when configuring your source folders
When your project uses compile-time localization features you have to add the corresponding resource bundles to the classpath. If at some point you change the statically specified language you have to change the resource bundle classpath. One way to avoid this is by using the special {locale} token when specifying the source folder. Imagine your bundles are in bundle/es_ES and bundles/en_US. You can add the source folder bundles/{locale} then whenever you change the locale of your application (through compiler arguments) the specific source folder will be used as needed.
 

 
Create a common configuration project

An application is usually made up of several different projects: shell, modules, common libraries, component libraries, and so on. Even though they're not directly related, there might also be static resources that can affect all projects. These can be stored in a CommonConfiguration project. Such a project might include:
 
  • Common libraries. Frequently different projects (or modules) use the same libraries (for example the application framework, efflex, flexlib, flexmdi, and others). If each individual module or project distributes its own SWC file it's highly probable that at some point each project will end up using a different version of the SWC, messing up the final compiled SWFs. Also, in applications with lots of projects, it can be an important time saver to distribute the SWCs in a centralized way. The way to do this is to create a libs folder in a CommonConfiguration project. From each of the other project a SWC folder reference can be added to the classpath (using relative paths: ${DOCUMENTS}/CommonConfiguration/libs). If at some later point a library is updated in the CommonConfiguration project all the dependent projects will be updated.
  • FlexFormatter. To reinforce collective code ownership it's important that the team agrees on using some common formatting rules. A plug-in like FlexFormatter can then be used to enforce them. If you use FlexFormatter, you can configure your rules, export them to a flexFormatter.properties file, and store this in the CommonConfiguration project, so that every developer in the team can use them.
  • Shared compiler-config.xml. As explained above, a nice way to set additional compiler arguments is by using the -load-config compiler argument. This argument can be overloaded, which means that you can specify several different configuration files. If all your projects share some arguments ( -keep-metadata is a good example), you can store all the common parameters in a configuration file within the CommonConfiguration project.
  • readme.txt. Normally it's very handy to have a simple text file with the basic details on how to set up the environment. You can include which linked resources and variables are needed, which Ant target needs to be executed to build the project, and so on.
  • A FlexPMD custom ruleset file. If you're using FlexPMD and a ruleset specific to your project or team, you can make the files easily available to other developers by including them in the CommonConfiguration project.

 
Where to go from here

This article provided a set of best practices that can help you and your team improve your project setup. When applying these guidelines, it should be easier to on-board new developers more quickly and make configuration changes, such as updating libraries, seamlessly without disrupting development work. You may be able to apply some of the tips to your current team, while others might be more suitable for future projects. In either case, it's a good idea to keep these tips in mind to streamline your Flex development efforts.
 

Acknowledgements

Special thanks to Tom Sugden for sharing his best practices and good advice, and for his technical review of this article.