Accessibility
 
Home / Developer Center / Flash Communication Server Developer Center

Flash Communication Server Article

Icon or Spacer Icon or Spacer Icon or Spacer
Slovik Lozben
Slavik Lozben
Principal Engineer
Macromedia
 
Best Practices for writing Macromedia Flash Communications Server MX applications

This article provides a set of best practices for writing Macromedia Flash MX and Macromedia Flash Communication Server MX applications. It is important to write applications which can be easily modified later—by the original author as well as by developers who may be new to the project.

The nature of Macromedia Flash applications
Macromedia Flash applications can be scripted in a variety of ways. Given the range of possibilities, anything goes. While this flexibility allows for a wide variety of solutions to a problem, it also makes it difficult for anyone (other than the original developer) to understand the movie. Sometimes even the author of an application may have difficulty understanding their own movie a few months after they created it. This problem occurs primarily because there are few established coding standards for how to create a "good" Macromedia Flash application.
 
ActionScript conventions (by Robert Tatsumi)
·
Keep actions together. As much as possible, all code should be placed one location (preferably frame 1). This makes the code easier to find and debug. One of the main obstacles in debugging Macromedia Flash movies is finding the code. If most (or all) of the code exists in one frame, then this problem is eliminated. There may be exceptions to this rule. For example, when you are creating a pre-loading Flash movie, you may find it impossible to place all the code in frame 1. However, you should strive to place all your code in a centralized location.
·
Use #include .as files. This recommendation is mainly for larger, more complex movies. This practice is also helpful when multiple people are working on the same SWF. One of the main benefits of using include files is to allow the use of a source control system. This makes versioning and comparing code easier to manage.
·
Frames as application states. Use keyframes to delineate application states. Currently, many developers to use frames as states of the application and use inline code within a frame action to define the state of the application. This practice is not recommended. A better approach involves organizing the code, placing any actions necessary for this state into a function, and then calling the function as the only action performed on that frame. Alternately, an optimal strategy for organization involves creating two layers in your movie. One layer extends the full length of the movie and the majority of the code is located within this layer/frame. The second layer includes actions necessary for keyframe/state changes of the application. The only code on each keyframe is a function call into the main frame where the function exists.
·
Movie clip actions are discouraged. Movie clip actions should only be used when absolutely necessary. If used, only a minimum amount of code should be included, as in the following example:
  
    onClipEvent(mouseDown) {
        _rotation += 15; // rotate the movie clip by fifteen degrees
    }
·
Initialization. Use initialization code in your application to set the initial state. This should be the first call of the application. It should also be the only call made in your program. All other calls should be event-driven (for example, triggered by a frame event, a mouse event, and so on), as in the code below:

    // frame 1
    this.init();
    function init() {
        if (this.inited != undefined) {
            return;
        }
        this.inited = true;
        // do initialization here
    }
·
Scoping variables. All variables should be scoped. The only variables that are not scoped are function parameters and local variables. Absolute scoping (_root.myMovieClip.myVar.blah = 100) can lead to non-portable code. If variables are scoped to "this" and "_parent", the resulting code will be easier to port later. Use var for local variables. This prevents them from being accessed globally.
·
Use relative addressing. All variables should be scoped relative to their current path, if possible. Scoping off the root is not recommended—this limits the portability of the code. Use "_parent" or "this" instead. If you must use absolute addressing to the main timeline of the movie, use an accessor in the main timeline. This allows for easy modification of "this" parameter. To create a convenient reference to the main timeline of a movie, you should add this line to your movie's main timeline:

//(substitute the name of your application for "myApp")
_global.myAppMain = this;

You can then use _global.myAppMain.someFunction to refer to functions on the main timeline. This allows your movie clip structure to change.
·
"_root" vs. "_global". Know the difference between "_global" and "_root". "_root" is unique for each loaded movie. "_global" applies to all movies that exist within a movie. Generally, the use of "_global" is desired.
·
ActionScript coding standards by Mike Williams (in PDF format, 716K). This is a useful document which contains more scripting recommendations and best practices.
 
Macromedia Flash Communication Server MX: Application coding guidelines
This article is not intended to start a heated debate on coding styles. These suggestions are merely recommendations that may make it easier when designing the structure of an application. If a series of applications contain familiar structures, it makes it easier for a whole team of developers to understand and modify the applications as needed. Consider the following guidelines when you are developing:
·
How do you inherit from a class and still call the constructor of the parent class? The following code example demonstrates this:

/////////////////////////////////////
//
// How to Inherit from a class (sample)
//
/////////////////////////////////////
function PlayStream(nc) {
    // call NetStream constructor
    // note! super only works with client side programming, so
    // calling the constructor of the parent class is not possible
    // with server side scripting!
    super(NC);

    // set the buffer time
    this.setBufferTime(this.initBufferTime);
   
    // save the reference to the NetConnection object
    this.nc = NC;
}

// inherit from the NetStream object
// set the prototype to be NetStream
PlayStream.prototype = new NetStream();
// the rest of the new class definition goes here
·

When does the instance of the super class get created when you inherit from another class? The super class gets created whenever you access any methods of the super class. So, in the example above the super class gets created in the constructor of the inheriting class.

Note: Server-side scripting has no notion of the super class, so the super object never gets created. In most situations, this does not matter. It does matter if you inherit from a class which has native data structures created whenever that class is instantiated. For this reason, it is not recommend to inherit from predefined Flash Communication server-side classes.

·
When initializing default properties for a class, try not to do it in the constructor. It is much better to initialize these values during class definition via the prototype, as follows:

// set some default property values
PlayStream.prototype.initBufferTime = 10;
PlayStream.prototype.waitingForBufferEmpty = false;
PlayStream.prototype.timeTotalShadow = 0;
playStream.prototype.bufferTotalShadow = 0;


In general, any value which doesn't need to be initialized in the constructor should not be initialized there.

Ex.
function MyFavoriteClass() {
   this.init();
}
MyFavoriteClass.prototype.init = function() {
    this.x = 0;
    this.y = 0;
    this.z = 0;
};


If the only time the above init() is called is in the constructor, then the code above should be changed to the following:

function MyFavoriteClass() {
   // no init here
}
MyFavoriteClass.prototype.x = 0;
MyFavoriteClass.prototype.y = 0;
MyFavoriteClass.prototype.z = 0;
·

The rules for initclip are as follows: If you want users to be able to inherit from your component class, you need to provide and order for the initclip.

Ex.
#initclip 1
function FRadioButtonClass() {
    this.init();
}
FRadioButtonClass.prototype = new FUIComponentClass();
.
.
.
#endinitclip


When you provide order for the initclip, it lets the player know which initclip to execute first. You want to make sure that the object which you are inheriting from gets defined before you inherit from it. So if your component inherits from a component which has an "#initclip 4" in it's definition, your component then must issue an "#initclip 5" or above. There is no need to worry about what range your initclip will occupy. The only thing to make sure is that the initclip of your component has a higher order (number following the "initclip" statement) then the component you are inheriting from.

·
Override onStatus for all of Macromedia Flash Communication Server MX objects. This should be one of the first things you do, even if your application does not need to do anything in the onStatus callback. One strategy involves overriding the onStatus when you start writing the application, as shown below:

ex.
//+
// Trace all the status info
//-
function traceStatus(info) {
    trace("code is: " + info.code);
    trace("level is: " + info.level);
}
NetConnection.prototype.onStatus = traceStatus;
NetStream.prototype.onStatus = traceStatus;
SharedObject.prototype.onStatus = traceStatus;


Once you need to actually override the callback for a specific purpose you can delete the code above, but at least in the meantime you will always see all of the messages related to the communication server application. This will save a considerable amount of debugging time when you are getting started.
·
The style of the Macromedia Flash code beautifier is the preferred coding style. The page real-estate is valuable and this style uses the least amount of vertical space and gives the most information. If you feel strongly about your style we are not insisting that it must be changed. We realize that this could be a very serious obstacle for many in switching their curly parentheses location. We are simply suggesting a common style for all.
·
If you are inheriting someone's project, stick with the coding style which is already in place!

ex.
// if the style is
if (condition)
{
    statements
}
else
{
    statements
}

// don't switch to this style
// in the middle of the project
if ( condition ) {
    statements
} else {
    statements
}

·
Use the right suffix when declaring variables which are Macromedia Flash Communication Server MX objects as follows:
 
Supported Flash Communication Server suffix strings for code completion
(client side scripting)
Object Type Suffix String Var Example
Camera _cam
cam
some_cam
cam
Video _video
video
some_video
video
LocalConnection _lc
lc
some_lc
lc
Microphone _mic
mic
some_mic
mic
NetConnection _nc
NC
some_nc
NC
NetStream _ns
ns
some_ns
Ns
SharedObject _so
so
some_so
so
   
 
Supported Flash Communication Server suffix strings for code completion
(server-side scripting)
Object Type Suffix String Var Example
NetConnection _nc
NC
some_nc
NC
Stream _stream
stream
some_stream
stream
Client _client
client
some_client
client
Application (this a singleton object which is globally pointed to by the application variable) application application
SharedObject _so
so
some_so
so

ex.
main_nc = new NetConnection();
play_ns = new NetStream(main_nc);
·
In C++ it is common practice to precede the names of member variables of a Class with an "m_".

"C++" ex.:
class Person {
public:
    int m_height;
    int m_age;
    int m_weight;
};
Person::SetInfo(int height, int age, int weight)
{
    m_height = height;
    m_age = age;
    m_weight = weight;
}


This practice in C++ makes sense since, when reading code, many developers key of "m_" to assume scope. In ActionScript (or JavaScript) this practice would be redundant. You must always use the "this" specifier in the methods of a Class and so "m_" prefix is just not needed.

"JavaScript" ex.:
function Person() {
}
Person.prototype.height = 0;
Person.prototype.age = 0;
Person.prototype.weight = 0;
Person.prototype.setInfo = function(height, age, weight) {
    this.height = height;
    this.age = age;
    this.weight = weight;
}
·
Know the difference when marking a slot of a shared object dirty on the client vs. the server. Let's say that the shared object data property is list of objects of type Point. And let's assume you want to change the value of slot "23" to x = 46 and y = 78. The following code examples illustrate how to accomplish this task on the client and on the server.

ex. client
my_so.data[23].x = 43;
my_so.data[23].y = 78;


ex. server
var tmp = my_so.getProperty("23");
tmp.x = 43;
tmp.y = 78;
my_so.setProperty("23", tmp);
·
The preferred way to iterate through an unordered list is shown below:
ex.
for (i in objOrArray) {
    // do something with objOrArray[i]
}


This style allows flexibility, because it doesn't matter whether a list or an object is being referenced. It could be either an array or an object.
·
Make sure you understand the language differences between ActionScript on the client and ActionScript on the server. Here is a quick list of some of the most common differences:
Feature/key word client side scripting server side scripting
_global (object) yes no
System (object) yes no
super yes no
Object.registerClass() yes

no (use)

application.registerClass()

case sensitivity

no

yes
accessing an undefined variable
yes

will cause an assert. You must declare the variable first before checking its value

i.e.,
var foo;
.
.
if (foo == undefined)

function forward referencing style1

ex.
foo();
function foo() {
}

yes yes
try catch blocks no yes
·
How does one chain onSync, onStatus, etc. without destroying the previous callback? This code example provides an answer to that question:

ex.
SharedObject.prototype.attachOnSync = function(func) {
    if (typeof(func) != "function")
        return;

    if (this.onSync == undefined) {
        this.onSync = function(list) {
            for (i in this.onSyncList) {
                this.onSyncList[i](list);
            }
        }
        this.onSyncList = new Array();
    }

    this.onSyncList.push(func);
}
.
.
.
function myCallback(list) {
    // yada, yada, yada
}
my_so.attachOnSync(myCallBack);
·

How can you check for undefined variables on the client and on the server? Try the following:


//+
// on the client
//-
if (foo == undefined) {
    // do something here
}

//+
// on the server you must use the method below if you
// don't and the type is truly undefined the server script
// will throw an exception if you use the style above
//-
if (typeof(foo) == "undefined") {
    // do something here
}

 

Conclusion
This documents summarizes good practices when creating Macromedia Flash and Macromedia Flash Communication Server MX applications. The idea is to avoid common pitfalls which could lead you into trouble while creating sophisticated applications. Everything here is a suggestion. There are many styles and many philosophies which can be followed during application development. What is suggested here is the general practice of many Flash developers. Hopefully, there are some useful suggestions and hints here that you can practice in your own Macromedia Flash and Macromedia Flash Communication Server MX application development.

 

About the author
Slavik Lozben is a principal engineer on the Flash Communication Server team. He was involved in the design and implementation of many of the features in the product. Slavik joined Macromedia in January of 1995. He originally worked on the Director product line. When Macromedia bought what is now known as Flash, he saw a tremendous opportunity and joined Robert Tatsumi and Jon Gay, the creators of Flash. He has been on the Flash team ever since.