Introduction
I started working with Force.com back in mid-2012. My goal at that time was to learn all about the point-and-click, drag-and-drop, or better known as declarative development. Being a Software Engineer, I really wanted to get into code because that’s what interests and drives me. Regardless, I went through the Force.com Workbook for that year and picked up as much knowledge as possible. I discovered how powerful the platform is and how quick it can be to get something up and running (even in code, most boilerplate is done for you).
I didn’t touch it much after that and moved to different things at the time, mainly some fun development with ASP.NET MVC 3. However, several months ago, I’ve been participating in Force.com development that isn’t declarative at all. Rather, it’s a full application running on top of Force.com and uses Visualforce and AngularJS.
I’ve learned quite a bit about the platform when it comes to custom applications while writing Apex code for backend processes. My team has adopted an interesting development workflow based on the differences of the platform in contrast to ASP.NET MVC or Node.js development. This post will describe our typical development workflow.
Development Workflow
It’s important to keep in mind that since the Force.com platform is very different from other platforms or technologies on the market, our development workflow is rather unique. Granted, it’s quite possible that many of you who are reading this post right now who partake in Force.com development may find your development workflow similar. I’d love to hear about your workflow in the comments.
Prerequisites
To follow this development workflow, the following prerequisites must be accounted for. Moreover, keep in mind, this guide is written strictly for Windows users.
Setup Personal Developer Environment
Before getting started we must have a Force.com cloud environment to work with which will store our code, user settings, etc. This environment will be where we host our application. We can set up a free environment used for development and testing. In later stages of the development workflow, other cloud environments will be used which do not have the limitations of the free environment. However, for the moment, it should be more than sufficient for our development needs.
All that’s needed to get the free account is to visit developer.salesforce.com/signup. Fill out the form and then you should be in business.
- Install Eclipse (Java version) and configure the Force.com IDE plugin.
- Install a good code editor like Notepad++.
- Have a source control system in place, such as Git.
- Install a good file comparison tool such as Beyond Compare, WinMerge, or KDiff3.
- Optional: Install a good search program such as Agent Ransack.
Set up a Folder (Ideally in Root of C:) for Source Control
We need a place to store our metadata and all files to be part of our Force.com project. Creating a folder for this purpose is a must before continuing further. I recommend Git due to its powerful feature set and ease of use. If you aren’t into typing commands on the command prompt, then a great tool to use with Git is SourceTree.
Once you have a folder setup which is under source control, I suggest adding a .gitignore file to ignore items that aren’t recommended to be placed into source control. Below is an example of the file I use for this purpose.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
### Windows ### # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk ### ForceDotCom ### .project .settings salesforce.schema Referenced Packages ### Directory for ForceDotCom exports ### export/ ### Apache Ant ### build.properties build.xml # Ignore personal property files # my.build.properties my.build.xml poc.build.properties poc.build.xml # Ignore static resource containers (.resource files) *.resource |
Configure Apache Ant and Account for Metadata
Apache Ant is a deployment tool used with the Force.com platform. It is used to capture data from a Force.com environment and to deploy data back to that environment. Its settings must be configured to work with Force.com metadata. Everything in Force.com has metadata. It could almost be said that this data is the heart of the platform. It tells Force.com how to behave, and properly capturing it and deploying it is key before starting any kind of development. I suggest reading up more on metadata before continuing if you don’t have a firm grasp on it.
Apache Ant has three files that need to be configured to work with your instance of Force.com. However, before configuring those files, you need to ensure Apache Ant is installed and can work from the command line. Follow this guide before continuing. In addition, be sure to download the Force.com Migration Tool. This can be done by logging into your instance of Salesforce and going to Setup. Once there, search for tools and then download it. There will be a file named ant-salesforce.jar that needs to be copied to your Apache Ant lib folder.
Create the files described below and ensure they are placed into the root of the folder that is now under source control along with your .gitignore file.
build.properties — This file stores some important settings for Apache Ant to retrieve and make use of. Force.com usernames, passwords, instance URLs, and the local source path for where the metadata is stored can be found here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# build.properties # # Specify the login credentials for the desired Salesforce organization developer.username = john.smith@greatcompany.com.devenv developer.password = iShouldChooseAGoodPassword #sf.pkgName = <Insert comma separated package names to be retrieved> #sf.zipFile = <Insert path of the zipfile to be retrieved> #sf.metadataType = <Insert metadata type name for which listMetadata or bulkRetrieve operations are to be performed> # Use 'https://www.salesforce.com' for production or developer edition (the default if not specified). # Use 'https://test.salesforce.com for sandbox. developer.serverurl = https://login.salesforce.com developer.local.source.path = C:\\Force.com_Projects\\Project_Amazing\\src |
build.xml — This file contains all the instructions for Apache Ant to carry out. Such instructions include running test classes as part of a deployment, converting line endings to Unix format, automatically adding changed static resources to the appropriate resource file, and what metadata to work with based on the XML file referenced, usually package.xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
<project name="Example Build.xml for Ant" default="test" basedir="." xmlns:sf="antlib:com.salesforce"> <property file="build.properties"/> <property environment="env"/> <tstamp/> <!-- <property name="mydir" value='dev3-${DSTAMP}'/> --> <!-- <property name="mydir" value="code"/> --> <property name="mydate" value='${DSTAMP}'/> <!-- Remove Windows line endings and replace with Unix line endings --> <fixcrlf srcdir="${developer.local.source.path}" includes="**/applications/*.app **/classes/*.cls **/classes/*.xml **/components/*.component **/components/*.xml **/email/*.xml **/email/Project_Amazing_Email_Templates/*.email **/email/Project_Amazing_Email_Templates/*.xml **/labels/*.labels **/layouts/*.layout **/objects/*.object **/pages/*.page **/pages/*.xml **/permissionsets/*.permissionset **/portals/*.portal **/staticresources/*.xml **/staticresources/AllResource/css/*.css **/staticresources/AllResource/js/*.js **/staticresources/AllResource/lib/bootstrap/css/*.css **/staticresources/AllResource/lib/bootstrap/css/*.map **/staticresources/AllResource/lib/bootstrap/js/*.js **/staticresources/ProjectAmazingWebApp_Resources/css/*.css **/staticresources/ProjectAmazingWebApp_Resources/js/*.js **/staticresources/ProjectAmazingWebApp_Resources/js/*.map **/staticresources/ProjectAmazingWebApp_Resources/typescript/*.json **/staticresources/ProjectAmazingWebApp_Resources/typescript/Models/*.js **/staticresources/ProjectAmazingWebApp_Resources/typescript/Models/*.map **/staticresources/ProjectAmazingWebApp_Resources/typescript/Models/*.ts **/staticresources/ProjectAmazingWebApp_Resources/lib/bootstrap/css/*.css **/staticresources/ProjectAmazingWebApp_Resources/lib/bootstrap/css/*.map **/staticresources/ProjectAmazingWebApp_Resources/lib/bootstrap/js/*.js **/staticresources/ProjectAmazingWebApp_Resources/pages/*.html **/staticresources/JqueryDatatable/media/css/*.css **/staticresources/JqueryDatatable/media/js/*.js **/staticresources/PageResources/css/*.css **/staticresources/PageResources/js/*.js **/tabs/*.tab **/triggers/*.trigger **/triggers/*.xml **/workflows/*.workflow **/*.xml" eol="lf" eof="remove" /> <!-- dumps --> <target name="deployDev" depends="zip, deployCode" /> <target name="getCode"> <sf:retrieve username="${developer.username}" password="${developer.password}" serverurl="${developer.serverurl}" retrieveTarget="${developer.local.source.path}" unpackaged="package.xml" pollWaitMillis="10000" maxPoll="20"/> </target> <!-- deploys --> <target name="deployCode"> <sf:deploy username="${developer.username}" password="${developer.password}" serverurl="${developer.serverurl}" deployroot="${developer.local.source.path}" testLevel="RunSpecifiedTests"> <runTest>PA_UserServiceTest</runTest> <runTest>PA_ProfileServiceTest</runTest> <runTest>PA_AlphaTest</runTest> <runTest>PA_BetaTest</runTest> <runTest>PA_GammaTest</runTest> <!-- Additional test classes go here --> </sf:deploy> </target> <target name="deployCodeCheckOnly"> <sf:deploy username="${developer.username}" password="${developer.password}" serverurl="${developer.serverurl}" deployroot="${developer.local.source.path}" checkOnly="true" testLevel="RunSpecifiedTests"> <runTest>PA_UserServiceTest</runTest> <runTest>PA_ProfileServiceTest</runTest> <runTest>PA_AlphaTest</runTest> <runTest>PA_BetaTest</runTest> <runTest>PA_GammaTest</runTest> <!-- Additional test classes go here --> </sf:deploy> </target> <!-- zip resources --> <target name="zip" depends="zipAllResource, zipProjectAmazingWebApp, zipJqueryDatatable, zipPageResources"/> <target name="zipAllResource"> <zip destfile="src/staticresources/AllResource.resource" basedir="src/staticresources/AllResource" /> </target> <target name="zipProjectAmazingWebApp"> <zip destfile="src/staticresources/ProjectAmazingWebApp_Resources.resource" basedir="src/staticresources/ProjectAmazingWebApp_Resources" /> </target> <target name="zipJqueryDatatable"> <zip destfile="src/staticresources/JqueryDatatable.resource" basedir="src/staticresources/JqueryDatatable" /> </target> <target name="zipPageResources"> <zip destfile="src/staticresources/PageResources.resource" basedir="src/staticresources/PageResources" /> </target> </project> |
package.xml — This file is rather important because it contains the metadata which Apache Ant uses to retrieve or deploy the appropriate data. All custom object definitions are contained within this file as well as workflow rules, email template definitions, etc. Basically, anything you’ve customized on the platform which you want to capture and place under source control must be contained within this file. If it’s not in the file, then if you did a deployment, whatever you missed would be skipped. The same thing goes when extracting the data.
Creating the package.xml can be done in several ways. You can manually create it, but it’s important to read up on the different types of metadata definitions you’ll need to include in your file. This all depends on what you wish to capture from the platform. Here’s a sample to get an idea. Moreover, here’s an article describing how to construct it.
Something else that can be done to get a better idea of the package.xml file is to take a look at the one generated by the Force.com IDE if you decide to use that tool. You can also find various videos on this subject as well.
Finally, it is significant that you prefix all of your objects in Force.com. Since this is an environment that can be shared among multiple applications, naming collisions are likely to occur. Everything should be prefixed with something that describes your application, like PA_, short for Project Amazing. Thus, if you had a class named ProfileService then its final name would be PA_ProfileService. What you are mainly focused on is the API name. Keep in mind we cannot do this with standard objects as the name is already given for us, but anything we create, dubbed custom objects can have the prefix.
Other items in Force.com should have prefixes as well such as triggers. The bottom line is to prefix anything you can in contexts where a naming collision could happen. If you do this, you’ll save yourself a lot of time and headaches when doing a release in an environment where other applications exist.
Workflow Process
- Pull Latest Code and Deploy to Personal Developer Environment — After getting the appropriate code for your project under source control, pull the latest code from the repository. Using Ant, deploy the code to your own personal Force.com Developer Environment.
Force.com Development Workflow Every time a developer commits code to the repository, it will be important to pull that code and deploy it to your personal developer environment using Ant. This ensures everything is up-to-date and accounted for. Keep in mind you’ll have to properly put the code under source control and by that I mean choose what should be under source control and what shouldn’t (this was discussed previously). Moreover, getting your own personal environment initially configured to support your project requirements is a must. It’s best to have pre-deployment and post-deployment instructions recorded, as they’ll be helpful for any future releases.
- Create Branch for Fix or Enhancement — Before getting down and dirty writing a single line of code, be sure to create a branch in Git for whatever it is you are doing. There are a few good reasons for doing this. For starters, it ensures you can work in your silo and not have to worry about other code or changes affecting the work you are doing. You can resolve any code conflicts or merges later on when merging everything back into the appropriate development branch (don’t commit to the master branch). Creating a Pull Request is a great option as it allows changes to be reviewed before merging and keeps a record of such activities.Another great reason for creating a separate branch for your work is if you find yourself in a scenario where your Tech Lead or Manager wants you to pull the latest code and test something unrelated to what it is you are doing. You can easily switch to the appropriate branch and test things right away without worrying about your code being affected. It will remain safe in its branch. There are more reasons I could list, but these should give you the idea. I suggest adopting a Git branching strategy like the one found here. It takes a bit of time to set up and configure, but is worth it in the end, in my humble opinion. However, your mileage may vary on that, so use it as a guide, not a bible.Now it’s time to write some code. Be sure the code you are working on is to be deployed strictly to your personal developer environment first. In order for this to work, it depends on how you are writing your code to begin with.
Text Editor (ex: Notepad++) — If you are using a text editor like Notepad++ to work on code, you’ll likely be editing metadata locally on your hard drive. This includes Visualforce pages, Apex classes, triggers, etc. Anytime a file is edited that way, you’ll need to use Apache Ant to deploy those changes back to your personal developer environment.
Force.com IDE (Eclipse) — If you are editing or creating any code in the Force.com IDE, anytime you save something it will immediately get synced back to the server. However, this is more complicated as you’ll likely have a separate folder that has the project and files for use with the IDE and then another separate folder under source control. So how do you get your changes back in sync? Using a tool like Beyond Compare, you can compare the two files (the one you changed in the IDE with the one in source control) and then merge the changes. That way, you can account for those changes in source control. You may not have to use Apache Ant to deploy back to the server depending on what file you modified, since the IDE will have already pushed your changes to the server.
- Write Your Code and Test — Now it’s time to write your code using the method of choice (a text editor like Notepad++ or the Eclipse IDE with the Force.com plugin). Depending on the approach you take, getting everything synced to the server may be different (see above). However, once everything is in a state where it can be tested, that’s your next step. If an Apex classes are created or modified, creating/modifying the proper test classes and associated methods is vital. Furthermore, always test your application and UI to ensure it’s working the way as intended.Force.com requires at least 75% code coverage, and it’s a good idea to aim for higher. Your test classes will determine this number based on how they are written. One great way to check to see which lines of code are covered is to open the Developer Console and then run the tests directly from there. When you click on any of the test class results, it will show the code that is tested and show a green outline for lines of code that have been tested and red for lines that have not. I highly suggest always executing your tests anytime you do a deployment to the platform. If you use the Force.com IDE, then you’ll need to manually execute your tests, such as from the Developer Console as mentioned above. Otherwise, if you make your changes with a test editor, then you’ll need to use Apache Ant to deploy to the server. In that case, your build script should contain the right options to run all your test classes.In the previous build.xml example above, the option for running your test classes is already there, so use that as a guide. Each time you add new test classes, you’ll need to update this file. You should test everything in your personal developer environment and then, if applicable, test in your organization’s sandbox. I’ve found this approach the best as it tests in two separate contexts and certain issues that didn’t appear in one environment may appear in the other. This gives you another shot at solving problems. Thus, once everything tests out fine on your personal developer environment, you can then deploy to the sandbox and do further testing there. If everything checks out, then you can move to the next step.
Tip: Always run your test classes regularly. Waiting until the end to run test classes before a release is bad practice. Depending on how long you go without updating your tests, a large body of work could be waiting for you right before you release, and this could have a very negative impact on your schedule. Staying on top of it every day may require a bit of extra time, but it pays off huge eventually. Plan for extra time to tackle these tests.
Important Note: Out of the box, Force.com doesn’t have regression testing or more advanced automated testing features. Any developer knows how nasty regressions can be; they aren’t any fun. Why not find a solution to nip those in the bud now? There are solutions out in the wild that are worth investigating.
Static Resources: Force.com handles static resources very differently from other platforms. Static resources in this context are images, CSS & JavaScript files, etc. There is a limit to the size of each static resource and the size of all of them combined. When editing a static resource file under source control, you’ll generally find it under the folder named staticresources. You’ll also find other files with a .resource extension. This is an archive file that contains all the static resources for that particular context. Just editing the static resource file alone and then doing a deployment is not enough. In order for your change to be picked up by the platform, the updated file needs to be in its parent .resource file. Force.com uses the resource file to retrieve your static resources.
There is good news, however. The example build.xml file shown previously automatically adds any changed static resources back to the resource file. You no longer need to worry about adding it yourself. This happens when you use Apache Ant to do the deployment. Resources do not work the same way in the Force.com IDE, and I’ve always found it easier to use Apache Ant to deploy updated static resources.
- Create a Pull Request/Merge Code Back into Development Branch — Once everything checks out fine, then you can incorporate your changes back into the Development branch. You can do a merge, rebase, or even create a pull request. How this is done is entirely up to you. As always, be sure your commits have the proper details.
- Before Release, Create Release Branch, then Merge into Master — Once you are ready to do a release, create a Release branch and prepare everything here. Incorporate any last-minute changes into this branch, and then eventually do your release. Afterward, merge the Release branch with the Master and tag your Master with the appropriate release version number.
Conclusion
I’ve just gone over the Force.com Development Workflow that I (along with my team) currently use. I’ve found this workflow to be the best for our needs. You can certainly do things very differently from how I’ve described, and that is entirely up to you. It’s important to pick a workflow that works best for your given circumstances. Not every workflow will be appropriate to your situation. However, what I’ve listed here should give you some great ideas to follow and tailor your workflow.
It’s important to keep in mind that the Force.com platform is constantly evolving. This example workflow may not be applicable in the future. I haven’t covered MavensMate which is certainly worth exploring (thanks goes to my cohort for introducing this to me). Other tools will certainly be introduced in the future. I also haven’t discussed debugging on the platform, which is an entirely different topic unto itself.
Please share your experiences with your development workflow in the comments below. I look forward to reading them and banding together as a community to identify different methods of getting work done on the platform. Force.com is certainly very different from other so-called traditional software development methods I’ve used in the past and takes time to get used to. However, when you discover its power and unlock it, then you have a valuable set of tools available to achieve the goals which are important to you. That’s why identifying methods to work with it effectively is critical to everyone’s success.
As with any project, it is important to identify the correct technology to solve your business problems. With that being said, always weigh your options before committing to a particular technology/framework/etc. Know the pros and cons of each one and do your research. Happy Salesforcing.