9
Fourth World Scripting Style Guide Helpful tips for xTalk, ActionScript, JavaScript and other scripting languages Richard Gaskin Fourth World Systems Adapted from The Michael and Richard Style Guide, presented at the SuperCard Developer Conference in San Francisco, California, January 1996, and updated with Ken Ray for the LiveCode Developer Conference in Monterey, California, May 2006. With ten revisions so far, it was last updated 27 March, 2012. Copyright © 1994-2012 Fourth World Portions Copyright © 1994-1996 Michael Silver and Barnacle Software This document may be distributed freely only in its complete, unmodified form, including this header and copyright information. Abstract Scripting languages are often easier to learn than more formal languages like C++, but this ease of use can seduce us into use a less desciplined code style which is hard to read and costly to maintain. By adopting some of the best practices of formal languages, scripters can reduce errors and shorten development cycles. Keywords: scripting, fourth-generation languages, programming, code style, HyperTalk, Transcript, MetaTalk, SuperTalk, Lingo, Hungarian notation, naming conventions. Contents: Introduction General Scripting Techniques Top-Down Handlers Clarify Program Flow Comment Effectively Comments as Breadcrumbs: What? Bang! Hmmm Code for Reuse Code for Speed Naming Conventions Variables and Arguments Handlers and Functions Objects Introduction Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k... 1 de 9 2014-09-10 14:03

Fourth World - Scripting Style Guide

Embed Size (px)

DESCRIPTION

Dicas de codificação em LiveCode

Citation preview

  • Fourth World Scripting Style Guide

    Helpful tips for xTalk, ActionScript, JavaScript and other scripting languages

    Richard Gaskin

    Fourth World Systems

    Adapted from The Michael and Richard Style Guide,

    presented at the SuperCard Developer Conference in San Francisco, California, January 1996,

    and updated with Ken Ray for the LiveCode Developer Conference in Monterey, California, May2006.

    With ten revisions so far, it was last updated 27 March, 2012.

    Copyright 1994-2012 Fourth World

    Portions Copyright 1994-1996 Michael Silver and Barnacle Software

    This document may be distributed freely only in its complete, unmodified form, including thisheader and copyright information.

    AbstractScripting languages are often easier to learn than more formal languages like C++, but this ease of

    use can seduce us into use a less desciplined code style which is hard to read and costly tomaintain. By adopting some of the best practices of formal languages, scripters can reduce errors

    and shorten development cycles.

    Keywords: scripting, fourth-generation languages, programming, code style, HyperTalk, Transcript,MetaTalk, SuperTalk, Lingo, Hungarian notation, naming conventions.

    Contents:

    Introduction

    General Scripting Techniques

    Top-Down Handlers

    Clarify Program Flow

    Comment Effectively

    Comments as Breadcrumbs: What? Bang! Hmmm

    Code for Reuse

    Code for Speed

    Naming Conventions

    Variables and Arguments

    Handlers and Functions

    Objects

    Introduction

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    1 de 9 2014-09-10 14:03

  • At some point in everyone's career, we all write crappy code (except my friend Mark Lucas, but he's in a class by

    himself). You know the kind: You go back to it six months later to add new features or better error-checking,and you have no idea what you were doing. It's "spaghetti code", and it can eat a lot of time as you try to figure

    things out all over again. That's where this document comes in.

    A few healthy habits can make your code more robust and your workday shorter. While they may require a little

    self-discipline at first, if you find these practices useful and adopt them in your daily work they'll becomesecond-nature and eventually require no extra effort at all.

    There are many reasons to use good style practice when writing code, including:

    More easily read and understood code

    Consistency in a multiple-author environmentMake future enhancement more easily

    Turn out code you can be proud to share

    Impress the chicks (or dudes, as the case may be)

    The tips presented here reflect some of the best practices of many world-class scripters, and we should take amoment to acknowledge them here:

    Michael Silver, Ken Ray, Mark Lucas, and Mark Hanrek are some of the best SuperCard scripters I've known, and

    it was while we were sharing code that we discovered that we had each independently developed pretty muchthe same code style. The first draft of this document reflected our common interest in SuperTalk, and was

    accordingly more limited in scope. It was distributed as part of a panel discussion on scripting techniques at theSuperCard Developer Conference in 1996, the year SuperCard 2.5 won the Mac Eddy award for Best New

    Multimedia Authoring Tool.

    Since then this document has been revised many times, expanding its scope to include new tips for other similar

    scripting languages. Along the way I've collected valuable tips from a great many programmers, including ScottRaney, Kevin Miller, Steven McConnell, Jad Santos, and Alex Bronstein. With the things these folks have taught

    me, this document should hopefully be useful for scripters who prefer just about any HyperTalk dialect, and afew others besides.

    As you read these tips, you may feel at times that where you code style differs you kinda like it that way. That's

    okay. If it works for you, it don't need fixin'.

    These are only guidelines, and the more people use them the more easily people will exchange code happily,solve problems more quickly, spend more time with their families, and create an ever better world.

    Having said all that, it is never worthwhile to rewrite existing code simply to conform to these suggestions. Noris it worthwhile to stick to a guideline where the function or efficiency of the code is compromised. There is a

    fine line between making more maintainable code and more efficient code. It is up to you to decide where thatline is in your own code.

    This document is a work in progress. We use it here in the course of teaching and working with contractors, and

    accordingly it is always being ammended and enhanced as experience suggests and time permits. If you haveideas for tips and techniques which you would like to see included here, please email them to me at

    [email protected].

    With all that out of the way, here's the beef:

    General Scripting Techniques

    A few techniques for getting the spaghetti out of your code....

    Top-Down Handlers

    Some programmers will fight more ardently over whether to list their handlers top-down or bottom-up than

    they will over whether to order single-malt or blended. Bad priorities, IMO: pick one code listing method and be

    done with it, and spend your brawling time over more important things like whiskey.

    Code tells a story, and both top-down and bottom-up tell the same story but each with a different emphasis.Bottom-up code has core handlers at the top, with the functions that call them below, and system messages at

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    2 de 9 2014-09-10 14:03

  • the bottom. Top-down puts system messages at the top, the more complex handlers that use them below, with

    generalized utiliy routines at the bottom.

    Personally, I like to tell a story in the order in which the events occurred, and since events in a script begin with

    system messages, it seems a more natural reading to put those first.

    Clarify Program Flow

    One way to fight spaghetti code is to make sure your code's logic is self-evident. For example, if you have onelong handler which takes care of a variety of startup stuff, you could break that down into multiple handlers

    which handle only specific related tasks. If you use descriptive names, you'll have no trouble grasping how thefirst handler works:

    on startup InitMenus InitWindows InitPrefsend startup

    The extra time required by the interpreter to handle these separate calls is trivial, and isolating specific sets ofrelated routines in this way can help you track down the source of errors during debugging.

    One good technique for making sure your code's flow is evident is to write the comments first. Just make an

    outline of what the code needs to do in comments, then go back and fill in between them with the actualexecutable lines. This technique can also be useful in the early stages of tackling a difficult routine, helping you

    think through the stages needed to complete it.

    Many words in scripting languages can be abbreviated. Where available, use 'em. They save space, and by being

    visually less significant they help your variables and handler names stand out. Plus you'll save a little typing.

    You can use parentheses to group logical or arithmetic expressions or to clarify code:

    if (the vis of wd "myWindow") then

    instead of:

    if the vis of wd "myWindow" = true

    Also, always using "=" for comparisons instead of "is" will help make such comparisons stand out visually.

    When nesting conditions I've found it helpful to use a separate line for each condition, making use of the "\" line

    continuation character and putting the conjunction in all-caps to draw attention to it:

    if (tWd is among the lines of the windows) \ AND (the vis of stack tWd is true) \ AND (the mode of stack tWd = 1) then ...

    end if

    This means a few extra characters when you're typing, but the clarity is well worth the effort. Conditional

    expressions are the heart of complexity, and the more complex your code is the more difficult it can be tomaintain and enhance. Giving them a little extra attention when you write you code can pay big dividends down

    the road if something breaks.

    Comment Effectively

    As a general rule, it's useful to comment any block of code whose functionality is not immediately self-evident.

    For example, it's merely distracting to see:

    -- Set the cursor to watch:set the cursor to watch

    But it's very helpful to have a brief note like this for more complex blocks:

    -- Update each card with the current date:

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    3 de 9 2014-09-10 14:03

  • set the cursor to watchput the short date into tDaterepeat with i = 1 to the number of cds put tDate into fld "Date" of cd iend repeat

    Comments can also be used as visual guides, separating different sections of code. Here's an example of howsets of related handlers can be grouped visually using commented lines:

    --=============================================--

    -- WINDOW ROUTINES--

    --

    -- DocWindowRect()--

    -- Returns the default size for new document windows--

    function DocWindowRect put the screenrect into r add 4 to item 1 of r add 4 to item 2 of r subtract 4 from item 3 of r subtract 4 from item 4 of r return rend DocWindowRect

    --

    -- UpdateAllWindows--

    -- Allows each open window to refresh itself--

    on UpdateAllWindows put windows() into tWdList repeat for each line tWd in tWdList send "UpdateThisWindow" to tWd end repeatend UpdateAllWindows

    --=================================================--

    Note that the example above also includes a brief description of each handler. This makes handlers stand outmore clearly when skimming, and provides a useful overview as to its purpose.

    You can also use comments to separate blocks of code within a handler, like this

    on MyHandler global gMyGlobal --

    SomeStatementHere AnotherStatement --

    StatmentForSomethingElse MoreOfThatend MyHandler

    By breaking code into blocks with comments you can make groups of related statements stand out from the restof the code. And by using blank lines only between handlers but not within then, you can skim through the code

    more easily.

    You'll want to use comments liberally if you're not concerned about script size. SuperCard, HyperCard, and a

    few other scripting environments have a 32k limit on the size of a script, so if you run into this limit you makewant to use only important descriptive ones and ditch those used as visual separators to save space.

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    4 de 9 2014-09-10 14:03

  • Comments as Breadcrumbs: "What?" Bang!" "Hmmm"

    In a perfect world all the code we write would be written with complete confidence that it's perfect the first

    time out. But the real world is much muckier, and often we code in ways that we know aren't optimal, but wehave to get something working now so we sacrifice quality or completeness for time. Merde happens, even on

    the most well managed projects.

    When we write suboptimal code it can be useful to leave some sort of marker identifying it as something we'llwant to revisit later on. We use a convention we call "What? Bang! Hmmm".

    The goal of "What? Bang! Hmmm" is to leave specific types of comment tags which can be searched for later to

    revisit portions of scripts which may need revision, sort of like leaving breadcrumbs on your trail through thecode. The convention we use is designed to be simple to remember, and simple to type:

    --? What?These are sections of code about which we have questions, such as "Could this be made more

    efficient?" or "Does this handle all of the cases we might throw at it?" We use "--?" to identify these:

    on SetUserPrefs pPrefsRecord --? Should we add another param to handle multiple users? set the uData of stack "MyPrefs" to pPrefsRecord end SetUserPrefs

    --! Bang!These sections contain issues we know we want to address before shipping the final product, such

    as adding error checking or other critical things. A search for "--!" across the code base brings you

    right to them:

    function GetFileData pFile --! This will be replaced by Paul's specialized handler in the library --! he'll deliver for Beta 2: return url ("file:"&pFile) end GetFileData

    --| Hmmm

    These comments are for more general things which may deserve more attention than ordinarycomments but not as critical as What? or Bang! comments.

    on SetWindowLoc pWindow --| RG 060517 Revised to use framework function: -- set the loc of this stack to the screenLoc set the loc of this stack to fwAlertLoc() end SetWindowLoc

    Code for Reuse

    As you write, ask yourself if you'll be using this again. If so, break it out into a separate routine so you can callit from anywhere. If you see yourself typing the same lines into a new handler that you used earlier in another,

    maybe that's a good opportunity to break it out.

    When you write your handlers, try to make them as generalized as possible. If you can avoid using global

    variables do so, since anything dependent on other routines will reduce the chances of being able to use thisroutine again in the future. If you only need to read a value in a global, consider passing it into the handler as

    an argument instead.

    Another way to keep code portable is to remove references to specific objects. If you have a function whichcalculates the sum of two fields for example, a non-portable version might look like this:

    put SumFields()

    function SumFields return fld "Num1" + fld "Num2" + fld "Num3"

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    5 de 9 2014-09-10 14:03

  • end SumFields

    This handler only works if you have three fields using those specific names. You could make it more portablelike this:

    put SumFields(fld "Num1", fld "Num2", fld "Num3")

    function SumFields put 0 into tSum repeat with i = 1 to paramcount() add param(i) to tSum end repeat return tSumend SumFields

    Not only can this handler be used anywhere, by using the param and paramCount functions we can now returnthe sum of any number of containers, making it applicable for a great many more uses.

    When referring to objects, use names whenever possible. If the name cannot be known or may change, use the

    object's ID number. Try to avoid using the ordinal number of the object (e.g., "button 4"), as you may makechanges to the layout which will cause the script to break. Descriptive names also help you understand the

    purpose of the object.

    Name all objects (cd flds, grcs, wds, &c.). Stay away from using numbers unless your script depends upon thattechnique (and even so, you should still name them. I often use names like "Bookmark 1," "Bookmark 2", &c.).

    Code for Speed

    Because interpreted languages are generally slowed than compiled ones, speed is a more critical consideration.Here's a few tips for helping the interpeter do its job faster:

    Use spelled-out words for literals such as "comma" and "colon" where the language provides them. These

    are parsed more quickly by the interpreter.

    Always put string literals in quotes, even one-word literals. Never put numeric literals in quotes (unlessthe language requires it). This improves parsing speed, since otherwise the interpreter must check its list

    of variables for a match before determining that the string is to be used literally.

    Use numbers instead of textual numeric constants. (e.g. "put myVar - 10 into cd fld "myField"", not "put

    myVar - ten into cd fld "myField"")

    Perform repeated operations on variables, not fields. When accessing a field, the interpreter needs to doa great many additional things to set the text up, modify it, and display it. Putting the data into a

    variable first lets you work on it much faster, often by several orders of magnitude.

    Naming Conventions

    Many scripting languages tout their "English-like" syntax as one of their strongest benefits, and of course it is.But code serves a different purpose than narrative writing, so while readability is important we find that in

    production environments code is far more frequently skimmed than read. We don't often read an enitre script tograsp it's story; if we wrote the code we already know the general story it tells, and if we inherited the code

    base some someone else we'll likely read it only once. But in the course of debugging and enhancing the codebase we'll frequently skim for certain elements, specific tokens or patterns, and using naming conventions can

    help make the elements you're most likely to be looking for stand out visually from the rest of the code.

    In this section we advocate liberal use of what is commonly referred to as Hungarian notation, in honor of the

    famous Microsoft programmer Charles Simonyi, who is said to follow this practice obsessively. The value ofHungarian notation is that it provides a consistent method for determining the use and nature of a given

    container by its name alone, without having to look elsewhere in the code to find out where it came from, suchas whether it's global or was passed in as an argument. To varying degrees, this style has been adopted by many

    scripters in recent years, as is reflected in the product documentation for Revolution, SuperCard, and others.

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    6 de 9 2014-09-10 14:03

  • While it can be argued that naming conventions like "Hungarian-lite" make code less readable, it can make the

    code more skimmable, which is a far more frequent need over the life cycle of a code base.

    Variables and Arguments

    You can quickly identify whether a variable is local or global, or whether it was passed in as an argument, if you

    preceed the descriptive name with a lower-case letter to determine its type.

    Char Meaning Example

    g Global variable gMyGlobal

    t Local ("temporary") variable tMyVar

    sScript-local var* (sometimes called"static")

    sMyVar

    p Parameter (also called an argument) pMyParam

    k Constant* kMyNumber

    u User-defined (or custom) properties uMyProp

    * Runtime Revolution, MetaCard, and Visual Basic only.

    Note about "p": I've had a few readers suggest that "p" should not be used for parameters, and that

    scripters using Lingo and AppleScript more commonly use it to designate properties. I've had atough time finding published code libraries that use this convention, so if you find any drop me a

    note at [email protected]. This document is an ongoing work, and I welcome theopportunity to keep it up to date as new trends in scripting become evident.

    Associative arrays can be local, script-local, global, or passed as a parameter, so to preserve the typedesignation arrays are noted with a trailing "A", often in plural form to reflect its status as a collection, e.g.:

    gOpenWindowsAtPasswordsApSelectedObjectsA

    Some general tips for naming variables and arguments

    Declare all globals in the first line(s) of your code.

    If your language supports local variables, also delcare them at the top of your code before executable

    statements.

    Use globals sparingly. Code written with globals often has problems which are difficult to find since theglobals can be touched anywhere. However, if you need to use a global, you need to use a global.

    Always use variable names that are descriptive. Stay away from names like "temp," "var1," and other

    names which have no meaning. Use instead names like "tProjPath."

    The exception to the previous rule is counters which serve no other function except as an index within a

    loop. Traditionally, counters begin with the variable "i" and procede through the alphabet (next use "j,"then "k," then "l.") You do not need to use "j", &c., unless you are building a nested loop.

    In this example we use a number of these tips:

    on myHandler pNumPeople,pNames global gFilePath global kMaxPeople,kMinPeople -- constants --

    if pNumPeople > kMaxPeople then exit myHandler

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    7 de 9 2014-09-10 14:03

  • if pNumPeople < kMinPeople then exit myHandler repeat with i = 1 to the num of items in pNames put item i of pNames & cr after tFileData end repeat open file gFilePath write tFileData to file gFilePath close file gFilePathend myHandler

    Handlers and Functions

    Use all lower case, except where noted below

    Capitalize the first letter in all but the first word of any compound word (e.g. doubleClickList). This

    applies to handler and function names, variables, and lexicon of the language you are using.

    Capitalize the first letter in custom hander and function names.

    Example:

    on MyHandler global gFilePath --

    put cd fld "Names" into tNames set the directory to pFilePath put the files into tFileList put ConvertDirector(ytFileList) into tDirectory if tNames = tDirectory then pass myHandlerend MyHandler

    When used in libraries, most of the handlers will be for use by other components. But you may have somehandlers which are used only by other routines within the library, not intended for use by others. It can be

    helpful to distinguish these "private" handlers, so using a leading underscore ("_") character can help identifythese readily:

    on StartTimer _RunTimerend StartTimer

    on _RunTimer put the short time into field 1 if "_RunTimer" is not in the pendingMessages then send "_RunTimer" to me in 100 milliseconds end ifend _RunTimer

    Yes, we know this breaks the rule in the fourth bullet point above, but for a reason: because it's harder to copy

    such handler names, it draws extra attention to their more specialized use.

    Objects

    Object names are usually best left to the specific needs of the program you're working on, but there are some

    guidelines which may be useful in some cirumstances:

    Fields used as labels can benefit from a prefix of "lbl", making it easy to write repeat loops which skipover any field with that prefix while setting the values for others.

    Stacks, groups, and other objects which are used as templates cloned at runtime can benefit from using

    something like "TMPL" as a suffix to make them stand out in object lists.

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    8 de 9 2014-09-10 14:03

  • Objects which contain behavior scripts can be prefaced with a lower-class "c", to denote their special useas a sort of class definition as is commonly done in lower-level languages.

    Fourth World - Scripting Style Guide file:///C:/Users/meira/AppData/Roaming/Mozilla/Firefox/Profiles/09k...

    9 de 9 2014-09-10 14:03