Titanium

Titanium Basics: 11 Steps to a Maintainable App


Note: This post was originally published on Medium. Rene Pot is an Appcelerator Titan, long time member of the Titanium community, and runs the Slack Titanium Channel @Ti_Slack. For more, you can follow him on Medium and Twitter.

In this guide I will describe what I think is the proper way to structure an app. Note that opinions differ on this subject, but this is the way I always set up apps and it has paid off for me. Just take what you like from the tutorial and make it your own.

  1. Create an Alloy App
    Use Appcelerator Studio to create a new Alloy project. It is essential you use Alloy and not Ti Classic. Alloy is a great basis to create well structured apps as it is MVC.
  2. Use Alloy.js only for essentials
    I frequently see Alloy.js files that are hundreds of lines long with tons of global variables, functions and calculations. Alloy.js is executed on launch and all variables declared in it are actually Global. While this might seem useful, it really isn’t.

    Alloy.js is great for simple calculations of things you need throughout the entire app. For example, you have views throughout your app that require to be a width of 20dp less than the device width. If you calculate this in Alloy.js and put it on Alloy.Globals you can properly use it in all tss files in your app.

  3. Don’t abuse Alloy.Globals
    While simple variables can be on Globals, don’t put tons of variables and/or functions on Globals. These are things that are supposed to be in lib.
  4. Use the app/lib folder for methods to be used throughout the app
    The app/lib folder is great to put tons of functions you need everywhere in your app. In my experience it is even great if this function is only used within just one controller. It keeps the controller clean, and easy to maintain.

    Just be aware you don’t create massive files in the lib folder though. The easiest way to prevent this is to group certain functionalities in files. As you can create folders in the lib folder there can be an easy separation of concerns. For example, you have an app where a user has a profile and the user has to log in. You could create all functions in 1 file, but I recommend creating a “User” folder in the “lib” folder, and in that folder you have 2 files: Auth.js & Profile.js. Auth takes care of authentication (like login call, storing tokens etc) and Profile takes care of the user data. More functionality for a user? Create a new file with a correct name.

  5. Put configurations in config.json
    This might seem trivial, but many apps don’t have this. A lot of apps I see have settings in the app itself. Hardcoded API url’s everywhere. What you want instead is put the base url (https://api.example.com/) in the config.json file. Especially if this URL is different for the development and production environment. The config.json file has sections for each environment, use them! Properties stored in the config.json file can be accessed through Alloy.CFG.[prop]
  6. Use a theme for styling your app
    Most apps I see have any of these ways to style:

    1. Copy-paste color codes & fonts in all tss files
    2. Add styling to the Alloy.Globals namespace
    3. Add styling to the config.json

    The 3rd option is actually great, but I usually create a theme for just styling of the app. Within the theme you can create a new config.json, which will not pollute the “regular” config.json and keep that file clean. On compile both files will merge anyways but it makes it easier for you to maintain. To set up a theme, add this property to your regular config.json:

    
    "theme" : "themeName"
    

    Because this is in your config, you can even create different themes for different environments if you’d like.

    Next, create a new config.json file like this:

    
    /app/themes/themeName/config.json
    

    Next, populate your config.json like this:

    
    {
       "global": { 
          "design": {
          }
       }
    }
    

    Within design I usually create a fonts and colors property. So I can use a grey I decided on throughout the app, and change it in one go too. Just use this in tss:

    
    "#myLabel":{
        color: Alloy.CFG.design.colors.mainGrey,
        font: Alloy.CFG.design.fonts.mainText
    }
    

    If you use the same combo often you can do this same trick in app.tss and apply it to a class which you can use throughout the app:

  7. Use global styling in app.tss
    When you have Labels throughout your app that are all styled the same, you might want to centralise the styling instead of repeating it everywhere. Your app.tss in that case should look something like this:

    
    ".defaultLabel":{
        color: Alloy.CFG.design.colors.mainGrey,
        font: Alloy.CFG.design.fonts.mainText,
        left: 20,
        right: 20,
        textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER
    }
    

    Within any View you can then apply the class defaultLabel and it will get the styling defined in app.tss. Need to override 1 specific elements, do so within the tss of the controller.

  8. Don’t try to squeeze everything in one file
    When your app grows, so do your view/controller/style files. Prevent them growing too big. I’ve talked about this subject in Enhancing Titanium. All components of your view can be stripped out and put in a separate controller. This gives your app more space to breath and you can easier maintain the code. Got a button in your app that also have some fancy animation? No need to keep that in the View you use it, make it a separate controller and include it in your view with the <require> tag.

    When your controller file (.js) gets too big, try and see if you can move specific functions to the lib folder. With this you can keep logic within the lib folder and your controller stay clean.

  9. Start with i18n folders
    Even if your app only has 1 language, keeping texts within the i18n folder will make this easier to maintain. If you decide to add a language later anyways, you’ve already set up the correct structure and the app is able to handle it straight away. In tss files you can just use the L() function.

    
    text: L("MyTextVar")
    

    Even my simple apps I’ve published that only have a handful of strings I have i18n folders for. Try the same. Learn more about this subject in the docs.

  10. Don’t use Ti.UI.create…
    This is one of the topics that there is a lot of discussion about, but every time I end up using a Ti.UI.create… function it turns out to be bad for me. I always keep forgetting that there are create functions in my controller code, and when updating the UI I really have to search for those items. It is also hard to figure out which structure the elements are in. What their parents and children are. You need to read the entire controller before you can reliably say what the structure is.

    Instead, if you need an ad-hoc element in your code do:

    1. already have the element present in your view, but hidden
    2. If the element is more complex, make a new controller (preferable inside a folder to be able to categorise the controllers) and use require() within your controller to get that element and insert it in your view.

    So, just need to insert an ImageView so you can show the result of a picture taken with the camera? Have the ImageView hidden in your view. Is your picture result much complexer (eg. ImageView with a semi-transparent view on top, with text inside) you can still use this strategy, but if you use it in more than 1 place in your app it might be wise to make a new controller.

  11. Use folders
    You can use folders everywhere. Within your controllers/views/styles folders, or in the lib folders. Also within the assets folders it is possible to go deeper. Do so to make your app better maintainable. Got a group of controllers that are all about a “profile” put them in a “profile” folder.

    Tip: To make a controller/view/style file within a folder, you don’t have to create these files manually, or move them to a manually created folder. Just right-click on your project, choose “New > Alloy Controller” and then type “profile/page.js” as the name to create a controller named “page.js” within the “profile” folder. It will create the folder if it doesn’t exist yet, and will also do the same for a view and style file.

Final note

These are guidelines I try to stick with. There probably are more but I think these are a good start. Got more? Respond to this article and share your insights! Again, these are my guidelines. If you prefer something different, feel free to comment on them. I’m curious to your insights.