tag:blogger.com,1999:blog-44331149526405394782024-02-06T19:59:08.887-08:00Getting UnstuckRandom Tips & Techniques for Adventurous Administrators & Daring DevelopersAnonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.comBlogger63125tag:blogger.com,1999:blog-4433114952640539478.post-89829542739986390672019-02-16T07:45:00.001-08:002019-02-16T08:26:06.788-08:00Easy Enterprise Org SFDX and CLIAuntie Pat Tern started taking Step Dancing classes. "Break it down", is all she said.<br />
<div>
<br /></div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8c5BE4X9RNbt5tuzaY-t-jqVt3ZvpheXWy2n0tMubkCdIOtn4J-_gDvY4h6we4V86QD8wk85lfHELpEY_bbLujK2syScClOI05khzeogc3Mv_lzBvV5YIg38NKBpIlYkxjI_51GF4BjIO/s1600/manspread.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8c5BE4X9RNbt5tuzaY-t-jqVt3ZvpheXWy2n0tMubkCdIOtn4J-_gDvY4h6we4V86QD8wk85lfHELpEY_bbLujK2syScClOI05khzeogc3Mv_lzBvV5YIg38NKBpIlYkxjI_51GF4BjIO/s320/manspread.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Your new tools can coexist with existing User Interface options.</td></tr>
</tbody></table>
So I decided to break down my last post: <a href="http://www.snugsfbay.com/2019/01/easy-sfdx-for-enterprise-and-others.html">Easy SFDX for Enterprise and Others</a> to prove just how easy it is with 6 simple steps for application lifecycle management with SFDX for the Enterprise.</div>
<div>
<br /></div>
<div>
The Command Line Interface (CLI) for SFDX can be accessed via menu options in Visual Studio Code, or through the terminal, or through a Windows Command Prompt. So I'm going to use the CLI commands in the steps for the most clarity. And I'm assuming you've enabled the Dev Hub from your Production Org via the Setup options in the Salesforce UI.</div>
<div>
<br /></div>
<h3>
Step 1</h3>
<h4>
SFDX force:org:list <br /><span style="font-weight: normal;">Shows which orgs you are connected. You want to connect to your sandbox orgs to manage your development lifecycle, for example: developer, integration, staging.</span><br />
<span style="font-weight: normal;"></span><br /><span style="font-weight: normal;"></span></h4>
<h3>
Step 2</h3>
<h3>
<span style="font-size: small;">SFDX force:auth:web:login -r <i>https://test.salesforce.com</i> -a <i>orgAlias</i> -s</span><br /><span style="font-size: small; font-weight: normal;">Connect a sandbox where you will find and update source code and configuration. </span><br />
<span style="font-size: small; font-weight: normal;">Text in italics will need to be specified by you when you run, and should apply to your work.</span><br />
<span style="font-size: small;">-r <span style="font-weight: normal;">is followed by the login URL for the org, using test subdomain for sandboxes and login subdomain for your Production org. Be very careful when connecting to Production, test changes before you deploy them, of course.</span></span><br />
<span style="font-size: small;">-a <span style="font-weight: normal;">is followed by an alias you are giving to this org connection. Something like 'Dev' for a developer sandbox maybe? 'Int' for an integration sandbox. You see where I'm going here.</span></span><br />
<span style="font-size: small;">-s <span style="font-weight: normal;">indicates that this should be the default org and username for your current work and is important to remember. You can also check the force:org:list to make sure you know which org you are working in at all times.</span></span><br />
<span style="font-size: small;"><span style="font-weight: normal;"><br /></span></span></h3>
<h3>
Step 3</h3>
<h4>
SFDX force:mdapi:retrieve -p <i>somePackage</i> -r <i>r###</i> -u <i>orgAlias </i>-s<br /><span style="font-size: small; font-weight: normal;">Bring code and configuration from your org down to your local computer in a package.xml file. Text in italics will need to be specified by you when you run, and should apply to your work.</span><br />
<span style="font-size: small;">-p<span style="font-weight: 400;"> </span><span style="font-weight: 400;">is followed by a package name, either outbound change set or package defined inside a Salesforce org. </span>
<br />-r <span style="font-weight: normal;">is followed by the directory name on your local computer where the package will be saved.</span>
<br />-u <span style="font-weight: normal;">is followed by the alias for the connected org where your package/outbound change set was defined.</span>
<br /> -s <span style="font-weight: normal;">indicates a single package structure for the xml file.</span><br />
<span style="font-weight: normal;"><br /></span><span style="font-weight: 400;">The code and configuration should be defined in your existing org using either Setup>Package Manager to automatically include all dependencies and get a ton of related metadata or using Setup>Outbound Change Set just to get the specific code and/or metadata that is changing. </span><br />
<span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">Packages are super helpful and can be pre-defined in Production so that it is easy to see the full extent of code and customization dependencies related to your custom features. These pre-defined packages carry over to sandboxes you create for super easy org management. Don't upload it, we just want the definition of what it contains, and we want to keep that open and changeable. </span><br />
<span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">Creating and retrieving an outbound change set in the sandbox where you are starting development gives you a more manageable set of metadata and code, just the bits you need right now. Keep the change set open, don't define any deployment connections, we just want the definition of what it contains and we want to be able to add and remove if necessary.</span><br />
<span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">And of course you can create code locally with commands like </span><span style="font-weight: 400;">force:lightning:component:create and save or deploy those creations to your development sandbox for testing.</span><br />
<span style="font-weight: 400;"><br /></span><span style="font-weight: normal;">I should mention that these outbound change sets and in-org package definitions are all available with Workbench for retrieve and deploy as well, just in case your admins and devs love a familiar UI.</span><br />
<span style="font-weight: 400;"><br /></span></h4>
<h3>
Step 4</h3>
<h4>
Unzip<br /><span style="font-size: small; font-weight: normal;">Using your favorite tools, unzip the "unpackaged.zip" file you just saved to your specified local directory. Maybe you use a favorite application for zipping and unzipping, maybe jar xf from the command prompt. </span><br />
<span style="font-size: small; font-weight: normal;"><br /></span>
<span style="font-size: small; font-weight: normal;">You can now work with this code and configuration in any local app you choose, maybe VS Code. Make sure to save your changes back to your sandbox org. Run automated tests in the org using your favorite tools, check out Setup>Custom Code>Execute Tests.</span><br />
<span style="font-size: small; font-weight: normal;"><br /></span></h4>
<h3>
Step 5</h3>
<h4>
Backup with version control<br /><span style="font-size: small; font-weight: normal;">Save to your favorite repository for backup and version control. You can run git commands from the command prompt or you can literally just drag and drop with cloud-based interfaces for GitHub and BitBucket. You can also connect tools like VS Code to your repository to help you do this automatically.</span><br />
<span style="font-weight: normal;"><br /></span></h4>
<h3>
Step 6</h3>
<h4>
<span style="font-size: small;">SFDX force:mdapi:deploy -c -d <i>r###</i> -u <i>orgAlias</i> -w <i>100</i> -l RunSpecifiedTests -r <i>testa, testb</i><br /><span style="font-size: small; font-weight: normal;">Deploy changes to the next sandbox as you move your work through the various lifecycle stages. Text in italics will need to be specified by you when you run, and should apply to your work.</span></span><br />
<span style="font-size: small;">-c <span style="font-weight: 400;">optionally check the deployment before removing this flag and deploying for keeps.</span><br />
<span style="font-size: small;">-d <span style="font-weight: normal;">is followed by the local directory name where you have your work and package file (hey, it was '</span>-r<span style="font-weight: normal;">' before, but now it is not). You can even do a quick retrieve from sandbox to make sure you are deploying the latest version you tested in the sandbox org.</span></span><br />
<span style="font-size: small;">-u <span style="font-weight: normal;">is followed by the alias you have given to the </span><i>destination org </i><span style="font-weight: 400;">you set up previously. Not the org you made changes in and tested in, but the org you are deploying changes to for further testing.</span><br />
<span style="font-size: small;">-w <span style="font-weight: normal;">is followed by a wait time and is used for especially long running deployments.</span></span><br />
<span style="font-size: small;">-l RunSpecifiedTests <span style="font-weight: 400;">optionally lets you exclude long running or unrelated tests, otherwise expect all your tests to run in the destination org, even bulk tests. Combine this with the </span>-r<span style="font-weight: normal;"> option below:</span></span><br />
<span style="font-size: small;">-r <span style="font-weight: normal;">is followed by a list of test classes. Keep your bulk tests in their own classes and separate from unit tests so you don't have to run them during production deployments if you don't have to, for example.</span></span></h4>
<span style="font-weight: normal;"><br /></span>
<span style="font-weight: normal;">Done. You can look at the Deployment Status right in the destination org, using Setup options you already know.</span><br />
<span style="font-weight: normal;"><br /></span>
<span style="font-weight: normal;">Four super helpful SFDX CLI commands can really get help you break down your development lifecycle and use new tools where they are most helpful while keeping all the familiar Saleforce UI options to support your orgs and your users and to maintain those valuable audit records for changes in your Enterprise org.</span><br />
<h4>
<span style="font-weight: normal;"><br /></span></h4>
<div>
<br /></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-57663070744460441252019-01-19T09:53:00.002-08:002019-02-16T07:51:34.923-08:00Easy SFDX for Enterprise and OthersWhen cousin <a href="https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it">Tim Toady</a> took the doorknob and lock apart on the back door after his key broke, he had a lot of trouble figuring out how to put it back together. With a hundred tiny pieces laid out across the kitchen, <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> sifted out a dozen of the most important, handed it to cousin Tim and told him to just use that for now. Unsatisfied, Tim tried to put a few more parts back in, triggered the spring and the entire thing exploded across the kitchen again.That's when Auntie Pat Tern reminded him of two guiding principles: 1) Keep It So Simple and 2) Keep track of all your changes. He could have taped each piece to a sheet of paper, in order, as he dismantled the lock, for example.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNh1sQAKtG5iGiHHidzwOLKnAX3sI6sZUKSmG4ivncKoZ0u2woBGjCKvrSde6XOjf7lBMV9mXPNDQCfk-0KHndkmxxMhV7Z1dzyAXSee9knLKkrEpi1AXqWnFlL2qE6OAfvPYQ_9hdsTI0/s1600/sfdx2.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="354" data-original-width="1032" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNh1sQAKtG5iGiHHidzwOLKnAX3sI6sZUKSmG4ivncKoZ0u2woBGjCKvrSde6XOjf7lBMV9mXPNDQCfk-0KHndkmxxMhV7Z1dzyAXSee9knLKkrEpi1AXqWnFlL2qE6OAfvPYQ_9hdsTI0/s320/sfdx2.png" width="320" /></a>That reminded me of the guiding principles behind implementing Salesforce Developer Experience for the Enterprise Org. Staying Agile means finding the Minimum Viable Product for tools you implement, not just products you build, so here is my guide to easy SFDX for the Enterprise. (See <a href="http://www.snugsfbay.com/2019/02/easy-enterprise-org-sfdx-and-cli.html">part 2</a> of this post for the actual commands.)<br />
<br />
<h4>
SFDX MVP</h4>
<br />
1. <b>Discover: </b> A little reading reveals that SFDX is intended to "enable source-driven development, team collaboration with governance, and new levels of agility". To accomplish this, it offers the important benefit of using "developer tools you already know." Use what you know, that's easy.<br />
<br />
One thing we know in our Enterprise orgs is that configuration changes may happen in Production to meet immediate release requirements. So the Production org itself is always the absolute source of truth for the org. You can't just implement source control and claim that the source of truth is there because the bugs your users report will be found in Production and hopefully easily reproduced in Sandbox, that easily created org copy that is a developer tool you already know.<br />
<br />
So the first step is to use the developer tools you already know: Production is source of truth for code and metadata and Sandboxes provide great individual and team test environments. Keep them all. Use Dev Hub in Production to enable command line logins to these orgs.<br />
<br />
<b>2. Develop:</b> SFDX includes a Command Line Interface (CLI) that lets you connect to your Enterprise Production org as well as your Sandboxes using simple and batchable commands. That gives you the power to make use of local tools, including local code editing and version control by connecting the CLI to your orgs and pulling down the code to edit locally.<br />
<br />
Different Developer Sandboxes and different bits of code on the local computer make keeping track of all the versions and making sure they are merged and integrated into the larger system for testing means that version control is more important than ever.<br />
<br />
For version control, we use Git on the local computer and cloud-based systems like GitHub for team backups and version control. Our local git directory can be connected to our own personal branch (or maybe to a feature branch) of the org repository in GitHub. Following tech review, developer branches can be merged into the main code branch. And this can be automated so that a developer's work gets backed up from their local computers to the cloud repo on a regular basis.<br />
<br />
You already know about backups and version control if you use something like Microsoft Word. It periodically auto-saves the working version of your documents. If your computer crashes, you have a choice between loading a version you saved or a version that Word automatically saved. Version control to the rescue! That can definitely be useful when you are doing Test Driven Development and your test fails because of your last set of changes and you decide to roll those back to the previous successful version.<br />
<br />
If you use Git for version control of your work on your computer, you can keep track of versions. And you can post those versions to GitHub, BitBucket or similar. These tools can make team collaboration easier with everyone checking their latest working version into the repository in the cloud. It's like the difference between Word on your local computer and Quip Documents in the cloud. Collaboration can be simplified with cloud solutions. And you can create a process for branches that get merged into a single main repository based on your own team's organization.<br />
<br />
We have different repositories for different platforms we develop on. And developers are free to create their own repositories for their own organization as well. One developer keeps every feature in separate branches and another developer keeps just a local repo and a cloud repo, no branches. For our org-wide repository, we have branches based on releases so that short-term and long-term projects are kept separate.<br />
<br />
The CLI adds flexibility to our Development Cycle by letting individuals choose tools they are familiar with and develop code locally or continue to develop in the Dev Console even, either way we can create a single shared backup and version control repository of everyone's work thanks to simple CLI commands.<br />
<br />
<b>3. Retrieve and Deploy: </b>Following our SFDX process of using what you already know, we can easily coordinate the efforts of admins who make configuration changes in Sandbox into our version control as well as developers who want to edit code with apps they run on their own computer. Salesforce provides two easy tools to work with the CLI: Packages and Outbound Change Sets. If you haven't tried both, take a look in Setup>Home for them.<br />
<br />
Packages give you the chance to define related sets of custom code and custom configuration metadata. Choose a bit of code and dependency data like custom objects and fields are automatically added. You can create Packages to look for overlap of functional dependencies in your org. And to help you document feature specifications.<br />
<br />
Outbound Change Sets give you a bit more control to stick to only code and configuration that has immediately changed, and not include more stable code and configuration from prior development that is already in Production. You can use these to get the most up-to-date configuration changes on the fly from production for anything you need to work on.<br />
<br />
Both Packages and Outbound Change Sets can be pulled out of the org and onto the local computer using the CLI retrieve command. These can also be deployed to any other org (yes, including Production) using the CLI deploy command. Retrieve pulls down a Zip file including a package.xml defining what has been retrieved and folders of metadata, all the same for packages or change sets. You can unzip this into your local Git directory to update your version and you can use the CLI to deploy back to any org after you've made changes. In between, backup ongoing work to shared repositories to merge changes for the next stage of the development cycle.<br />
<br />
Sticking with these familiar tools, we not only keep it simple, but we ensure that Admins and Devs can work well together because the org remains the source of truth and work efforts can be tracked, changes can be audited all in the org as usual.<br />
<br />
<b>4. Iterate:</b> Since we have the ability to connect to our familiar Enterprise orgs as well as the ability to work on changes locally and use tools for searching and comparing code and configuration versions, we create a stronger collaboration. Since we can use Git commands on our local computer to manage the backup and version control, we have even better insights along the development cycle, regardless of Sandbox refreshes.<br />
<br />
With changes happening in a variety of orgs, local repositories may need to rebase if a branch gets too far our of sync. For Enterprise orgs, the source of truth is what your users see when they report bugs and praise new features. So bringing your local repository back into sync with upstream changes is simplified.<br />
<br />
If you have separate repositories for each development stage from Integration to UAT, Staging, and Production, developers can retrieve changes at each point in the process. This makes it even easier to compare versions when a feature breaks after an upstream deployment. Verifying whether the correct version was deployed with all of its component parts can be done locally, in shared repositories, and by auditing recent deployments right in the orgs. And reverting to another version of a feature is even easier when you have backups in version control at each step.<br />
<br />
<h4>
Benefits of Change</h4>
<br />
SFDX helps Enterprise orgs follow Auntie Pat Tern's advice: Keep It So Simple and keep track of all your changes. By allowing admins and devs both to work with tools most familiar to them, at the same time, SFDX offers greater insight and transparency into the development cycle. Because the CLI opens up opportunities to make use of tools like VS Code and online repositories, debugging throughout the release processes may be simplified as well. And the CLI gives the power to make everything more automated for a more continuous integration of changes into each new environment at every stage of Enterprise development.<br />
<br />
Ultimately, the best implementation of the Salesforce Developer Experience is to make use of what you know and implement it your way, just like the SFDX Developer Guide recommends. Give yourself even more power with command line deployment and retrieval of packages pre-defined in your orgs through easy and familiar Salesforce Setup options. Get even more peace of mind with backups at each stage of the release process thanks to the CLI and Git local repositories connected to shared repositories online.<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-67858394244623661652017-11-17T10:46:00.000-08:002017-11-18T07:56:49.135-08:00The Eisenhower Matrix FallacyRoad trips reveal truths and clarify ideas, at least that's what my <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> insists. On a recent trip with her and cousin <a href="https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it">Tim Toady</a>, this came up when Tim requested a bathroom stop. What he said was, "I could use a bathroom some time soon." And as we flew past exit after exit, Auntie Pat Tern said he should let her know if it becomes urgent, otherwise she wanted to find a good spot to stop for lunch too. That got me thinking about competing interests when it comes to programming and the Fallacy of the Eisenhower Matrix.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3OVFW7Uwr17MiqRuJuptKXKwtQBBt9qjHWsCG4vekL-QcPDhbilrgMJYqBf-aTD6b5nef26XqO2DLFneUy_t3hlsRSv4Mvx5nZhSJppRXkIXWUkWWrlP35c5E5P0jgMGWR8uOooi-p9Lc/s1600/Duck-Rabbit_illusion.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="350" data-original-width="519" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3OVFW7Uwr17MiqRuJuptKXKwtQBBt9qjHWsCG4vekL-QcPDhbilrgMJYqBf-aTD6b5nef26XqO2DLFneUy_t3hlsRSv4Mvx5nZhSJppRXkIXWUkWWrlP35c5E5P0jgMGWR8uOooi-p9Lc/s320/Duck-Rabbit_illusion.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Jastrow, J. (1899). <span style="background-color: white; color: #222222; font-family: sans-serif; text-align: left;"><i style="font-size: 14px;">Popular Science Monthly </i><span style="font-size: xx-small;">US public domain</span><br /><span style="font-size: 14px;"><b>Duck or Rabbit?</b> It may depend on how long</span></span><span style="background-color: white; color: #222222; font-family: sans-serif; font-size: 14px; text-align: left;"><br />you allow yourself to analyze the problem.</span></td></tr>
</tbody></table>
<a href="http://www.presidency.ucsb.edu/ws/?pid=9991">In a speech at Northwestern University, President Dwight D. Eisenhower said</a> <i>"I have two kinds of problems, the urgent and the important. The urgent are not important, and the important are never urgent. " </i><br />
<i><br /></i>
<br />
<h4>
Prioritizing Competing Requirements</h4>
Important issues and urgent ones often compete. On our road trip, Auntie Pat Tern knew that a nice place to stop for lunch would also have a nice bathroom, that was part of her selection criteria. She also wanted to get as far as possible to her ultimate goal before the end of the day. Stopping both for lunch and for a separate bathroom pit-stop would delay her from reaching her ultimate goal. So she employed the Eisenhower statement as it was intended, to express that a thing cannot be both urgent and important.<br />
<br />
Unfortunately, a lot of people in the business world have worked Eisenhower's statement into a matrix, which suggests that requirements can be both urgent and important. Trying to accomplish a task as both important and urgent makes no sense. If it is important enough to need an optimal solution, then take the time to discover that optimal solution. If it is urgent enough to resolve immediately, do your best with what you have right now.<br />
<br />
Importance means you have the time to be thoughtful and take time to discover the most optimal solution; it is the polar opposite of urgency.<br />
<br />
As long as stopping for a bathroom break was important, it was worth waiting for the best location to stop both for food, which was also important, and for clean restrooms. But as soon as the need for a bathroom became urgent, the competing priority for food could be disregarded, at least to some extent. And with greater urgency, even the competing priority for a clean restroom might be set aside; the greatest urgency means you act now even if you have to pull off the road at that tree up ahead.<br />
<br />
<h4>
Eisenhower and Software Architecture </h4>
For software architecture, the urgent and the important need to be kept separate because the important parts of the project should inevitably be the most stable code in the system. The least stable code is the stuff you write out of urgency, when things are likely to change, but we can't wait until we understand all the factors that cause change.<br />
<br />
Don't believe the Eisenhower Matrix, it is a fallacy. Important and Urgent are like North and South ends of a magnet. Anything that is equally Important and Urgent lies in the middle, and that part of the magnet is neutral. The neutral zone is where we find the mindless and repetitive tasks that only become urgent when they are neglected for too long and only become important when something out of the ordinary arises.<br />
<br />
For Tim Toady on our road trip, he appreciated waiting for a sandwich on Dutch Crunch and a clean restroom because he values good food; it's important as long as he doesn't have more urgent needs.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-37808756362615883612017-11-12T09:10:00.000-08:002017-11-12T09:16:15.910-08:00Why Coders Use InterfacesGoing on a road trip with <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> and cousin <a href="https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it">Tim Toady</a> reveals a lot about them as only a road trip can. Tim was called a "whipper snapper" on more than one occasion for criticizing Auntie Pat Tern's driving. "I cannot wait for self-driving cars," he proclaimed while Auntie Pat Tern praised the freedom of the open road and the control she feels while driving a car. Which got me thinking about why interfaces are so important as part of my programming team's design decisions.<br />
<br />
Tim Toady prefers to drive arcade games while Auntie Pat Tern craves a 64 1/2 mustang convertible. But they both drive reasonably well in the electric car they have at home and the gas guzzler we rented for our long drive. That's because the interface of gear shift, accelerator, brake, and steering wheel are universally well understood by users.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiayjlbYTjlECETQ9sbrVZModTsXQdboUUsQAgxu9rT813bAzhVxHK9eE-wBLHUpbiUS0qRHGhLS0VSLVSwTdBy3iUDSX6aHDDO2_bwIK0-0rWlh4GeFHixMlmo9Z7g0c7mQIYGlPzGz2ME/s1600/happycar.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="449" data-original-width="440" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiayjlbYTjlECETQ9sbrVZModTsXQdboUUsQAgxu9rT813bAzhVxHK9eE-wBLHUpbiUS0qRHGhLS0VSLVSwTdBy3iUDSX6aHDDO2_bwIK0-0rWlh4GeFHixMlmo9Z7g0c7mQIYGlPzGz2ME/s320/happycar.png" width="313" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Accelerate, brake, steer, and shift. <br />The simplicity of a good interface.</td></tr>
</tbody></table>
That same interface translates inputs to a multitude of different systems from arcade games to tractor-trailer trucks. When it comes to deciding whether to accelerate or decelerate, the driver/user does not care if the vehicle is electric or gas-powered. A lot of people who drive electric cars even still say "gas pedal".<br />
<br />
Autonomous driving vehicles use the same interface as people: shift, accelerate, brake, steer. By using the same interface, a person can take over in an emergency, or maybe just for the fun of driving.<br />
<br />
Developers use good interfaces like this to future-proof their code. If the business rules are protected from the mechanism for inputting data thanks to a reliable interface, we can make sure the most important business rules continue to function as expected.<br />
<br />
Sure, sometimes the interface has to change a bit with new business automations. When cars got automatic transmissions, the gear shift changed and we lost the clutch. The same happens with code, new automations require small changes to the programming interface, but the goal of an interface is to minimize the need for such changes. Ultimately, we want to put interfaces between systems to give ourselves flexibility to support new automation, like Tim Toady's self driving car, as easily as we support more manual systems, like Auntie Pat Tern's stick shift.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-13414899075325445292017-04-05T15:59:00.001-07:002017-04-05T16:33:46.789-07:00Real Business Data Returns<a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> believes you can have your cake and eat it too, "Just use your resources wisely". So I wanted to see how to use my static resources more wisely in my Salesforce org. I have previously shown how to use <a href="http://www.snugsfbay.com/2016/07/what-load-of-business-data.html">static resources for test data</a>. Now, I want to use that same data in developer sandboxes created from my org. Since static resources are brought over like code to developer sandboxes, I can reference them in code I execute when I generate the sandboxes. Using the map datatype helps me keep relationships intact as well:<br />
<div>
<br /></div>
<div>
<script src="https://gist.github.com/snugsfbay/72cc67b3a1ab18e771f3d9150da108e9.js"></script>
</div>
With this simple trick, I can preload my dev orgs with sample business data that I am using in my unit tests. Like <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> promised, I can have my cake and eat it too when it comes to using <a href="http://www.snugsfbay.com/2016/08/csv-data-commonly-surfacing-vexations.html">realistic sample data</a> in my tests and development orgs.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com2tag:blogger.com,1999:blog-4433114952640539478.post-65386924947142642102017-04-05T13:04:00.000-07:002017-04-05T16:25:58.858-07:00Whole Heaps of Fun<a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> has noticed that questions about heap limits come up periodically. This could be a concern for developers needing to work with files and attachments in Salesforce. Luckily, those native objects aren't subject to typical heap limits. If you stick to blobs you can work with these large data objects. Don't use this knowledge to do bad things, now! Limits help us write code that performs well for our users as well as our fellow tenants in the multi-tenant environment we all know and love.<br />
<br />
12:52:35:797 USER_DEBUG [43]|DEBUG|Heap: 57,789,821 / 6,000,000<br />
<br />
Of course, if you test your code at limits, you can be sure of just how awesome your code is, which is another great reason to write thorough tests for all your code. You will find that if you are careful of what datatype you use and what you try to do with it the platform rewards you with heaps and heaps of fun.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-9757695881843580952016-09-28T10:37:00.000-07:002016-09-28T10:49:53.293-07:00Eliminate Cargo Cult Programming and Build a Stronger TeamMy <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> is one of those people who refuses to let family members wear cargo pants when we go out to dinner. She says she doesn't want to participate in the 'cargo cult'. She inspired me to look at how Cargo Cult Programming has affected our Salesforce org.<br />
<div>
<br /></div>
<div>
One of the best things about programming on the Salesforce platform is the wealth of resources online to help problem solve. It can be one of the worst things about programming on the platform as well if you aren't careful about the resources you choose to follow. Some code samples use outdated practices, others may be snippets of code taken out of context, which may not behave as expected in a different context.</div>
<div>
<br /></div>
<div>
In one case, the Apex documentation team included System.assert statements in a code snippet. Our new developer later copied the snippet into a utility class. The developer found a great resource but didn't fully understand the difference between System.assert and System.debug. The former builds in a fatal error, appropriate for test code but not for our essential platform automations. Sniffing out this cargo cult programming helped us know what additional training could help our developers.</div>
<div>
<br /></div>
<div>
A more frequently found cargo cult is the factory class to build basic objects. A factory class is still far better than using the very outdated SeeAllData in your test code. But test data factory classes add unnecessary work for coders. <a href="http://www.snugsfbay.com/2016/07/what-load-of-business-data.html">Salesforce offers a newer and better technique with Test.loadData</a>, which I wrote about in July. It lets us shift the work of creating and maintaining sample data from the developer to the administrator. </div>
<div>
<br /></div>
<div>
Other cargo cult programming that pops up in our Salesforce org relates to data sharing and security rules. We teach our developers early on to understand the difference between code that runs only in Triggers vs code that may be run by end-users via UI customizations like pages, flows and actions. And we encourage our administrators to monitor org security in our code during code reviews and test executions.</div>
<div>
<br /></div>
<div>
Hunting out and eliminating cargo cult programming helps us build cohesion among the team that maintains our Salesforce platform and better understanding between administrators and developers who now work more closely together. This helps us spread the effort of org maintenance across a team and make use of clicks and code for our projects. End users benefit and our org is more reliable and easier to maintain as well.</div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-12020662101143999452016-09-09T14:15:00.002-07:002016-09-09T14:16:58.569-07:00So Many Resources, So Little TimeI found <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> burying a hammer in the flower bed. When I asked why, she said it was <a href="https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it">Tim Toady's</a> favorite tool and he needed to learn something new. When all you have is a hammer, everything looks like a nail, so she wanted to make sure he found new ways of doing things. I like to make sure my developers are constantly learning new skills as well, so they don't rely on "golden hammer" practices that may have become outdated.<br />
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwOWYXvCqHqEQgOGxsoniAoUXwtBcKzv5rPK8XCt8scV0swakRWrmlczVt4ybgpRi1bJgU42yfT2kYwiWlT8tBeE-SBuhU9oWERjj2VfBpVmtdjStaaxEb_AWZZxddGRipI4s9v82pOZea/s1600/trailhead_superbadge_apex.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwOWYXvCqHqEQgOGxsoniAoUXwtBcKzv5rPK8XCt8scV0swakRWrmlczVt4ybgpRi1bJgU42yfT2kYwiWlT8tBeE-SBuhU9oWERjj2VfBpVmtdjStaaxEb_AWZZxddGRipI4s9v82pOZea/s1600/trailhead_superbadge_apex.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Become a specialist and then learn even more.</td></tr>
</tbody></table>
</div>
<div>
<br />
Learning to develop on the Salesforce platform is like finding a magpie's nest full of shiny objects. Where do you start and how do you figure out which gems are most valuable? Here's the path I take:<br />
<div>
<ol>
<li>Attend Dreamforce. The keynote and product demos will help you know what you want to learn. The sessions will help you get started on that learning. It offers the chance to talk to people who are on the same learning journey as you are and share tips and interests. I am presenting two sessions on developing with Apex this year: <a href="https://t.co/BuurBGre4v" style="text-align: center;">8 Essential Apex Tips for Admins</a> <span style="text-align: center;">and </span><a href="https://t.co/jAmtYiLbRH" style="text-align: center;">Apex Trigger Essentials for Admins</a>.</li>
<li>Watch more Dreamforce sessions online. After the event, Salesforce makes sessions available by video online. Sessions you wish you had attended, topics you didn't know you were interested in until after Dreamforce, all are free to watch online.</li>
<li>Follow up your learning in the Success Community. Find your <a href="https://success.salesforce.com/usergroups">local user group</a> and <a href="http://www.meetup.com/pro/salesforcedevs/">developer group</a> and follow the online conversations to learn how other people are using Salesforce and the challenges they are overcoming. Even if you don't have a local group, you can join groups online to be part of the discussions.</li>
<li>Keep up the learning with Trailhead. Salesforce offers online learning opportunities through Trailhead. Don't be intimidated by the <a href="https://trailhead.salesforce.com/en/super_badges">SuperBadges</a>, they offer a well defined path to learning about a particular skill in Salesforce. And if you get stuck the community is there to help.</li>
<li>Two places to turn for online help from the community when you get stuck on any of your coding projects are the <a href="https://developer.salesforce.com/forums/?id=906F0000000MIs9IAG#!/feedtype=POPULAR&dc=Apex_Code_Development&criteria=BESTANSWERS">Developer Community</a> and <a href="http://salesforce.stackexchange.com/">Stack Exchange</a>. Search the boards to see if someone has already asked about the question you have, and if you can't find a discussion, go ahead and post your question. Once you gain more skills, you should find that you are answering more questions than you are asking.</li>
</ol>
<div>
The resources are there to help you along. Learning to develop, or learning to develop even better, can be fun with all of the resources Salesforce offers. You don't have to rely on golden hammers when there are opportunities to learn new and better ways to work with Salesforce.</div>
</div>
</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-88846688340451350542016-08-07T13:46:00.002-07:002016-08-07T13:46:30.994-07:00CSV Data: Commonly Surfacing Vexations in DataAccording to <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a>, "Trying the same thing over and over without getting the results you want is enough to make anyone crazy." Unfortunately, that's the excuse Tim Toady uses when he doesn't do his homework because he's tired of not getting the results he wants from the effort.<br />
<div>
<br /></div>
<div>
When it comes to creating <a href="http://www.snugsfbay.com/2016/07/what-load-of-business-data.html">CSV files for use as unit test data</a>, what should be an easy process can make you a bit crazy if you wind up getting unfamiliar errors. The following steps and potential errors may help:<br />
<br />
<b>Step 1: </b>Export some production data.<br />
<b>Step 2: </b>Delete all but a reasonable selection of data.<br />
<b>Step 3: </b>Remove system fields.<br />
<b>Step 4: </b>Make sure the date fields are in the form YYYY-MM-DD<br />
<b>Step 5: </b>Make sure date/time fields have a "T" between the date and time, with no space, such as 2016-08-07T01:40:39<br />
<b>Step 6: </b>Make sure the commas that appear in text fields haven't thrown off the number of columns.<br />
<b>Step 7: </b>Make sure there are no blank rows with only commas and no values<br />
<b>Step 8: </b>Renumber IDs starting with 1<br />
<b>Step 9: </b>Remove any invalid IDs for related records (Account ID of 000000000000000AAA appears for all top-level accounts, and should be removed, for example)<br />
<b>Step 10: </b>Upload the CSV file as a Static Resource for your code to reference<br />
<br />
If you are creating a set of child records for an object that is related to another object, you can sort the parent and child data by the IDs of the parent to make sure you get records that match in both data sets. Use search and replace to redo the parent IDs to match the new IDs in the CSV file of parent records. For example, if you have a CSV for Accounts with IDs numbered 1-200, the related contact records must use 1-200 for the Account ID as well.<br />
<br />
Bad CSV files might result in the following errors:<br />
<br /></div>
<table border="2">
<tbody>
<tr><th>Potential Error</th>
<th></th>
<th>Likely Solution</th>
</tr>
</tbody><tbody>
<tr>
<td>Invalid ID value on line 2: 000000000000000</td>
<td></td>
<td>Remove invalid IDs</td>
</tr>
<tr>
<td>Too many DML rows: 10001</td>
<td></td>
<td>Load fewer records</td>
</tr>
<tr>
<td>CSV Parse error: '8/20/1959' is not a valid value for the type xsd:date</td>
<td></td>
<td>Format dates as YYYY-MM-DD</td>
</tr>
<tr>
<td>Duplicate ID value on line 81: null</td>
<td></td>
<td>Remove empty rows from CSV file</td>
</tr>
<tr>
<td>CSV Parse error: '2011-09-07 01:00:31' is not a valid value for the type xsd:dateTime</td>
<td></td>
<td>Format date/time fields with "T" rather than space between date and time</td>
</tr>
<tr>
<td>Validation Errors While Saving Record(s)</td>
<td></td>
<td>Erroneous data or IDs not starting with 1</td>
</tr>
<tr>
<td>System.UnexpectedException: Salesforce System Error</td>
<td></td>
<td>Remove stray commas throwing off columns</td>
</tr>
<tr>
<td>Static Resource not found</td>
<td></td>
<td>Make sure code refers to Static Resource by name</td>
</tr>
</tbody></table>
<br />
Start with a small number of records using the fewest fields for testing the code or configuration changes you need to test. That way, you won't wind up like Tim Toady, who falls back on <a href="http://www.snugsfbay.com/2016/05/seealldata-fail.html">bad habits</a> when errors occur with his first attempts to follow best practices.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com2tag:blogger.com,1999:blog-4433114952640539478.post-62279572868742889512016-07-31T15:47:00.001-07:002016-07-31T15:47:27.303-07:00What A Load Of Business Data<a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> thinks Superman's x-ray vision is stupid because "how would he ever know where he's supposed to look and where he should not bother focusing?" That got me wondering about the data and tests in my Salesforce org. Even clicks-not-code developers should have automated tests that validate configuration changes with existing and expected data. So what's the best way to know which data those automated tests should use?<br />
<br />
Some Salesforce developers like to write automated tests with "SeeAllData=True", an outdated and bad practice. A test that can see all data is not the same as a test that is smart enough to see the data that needs testing. For example, a good test will test positive scenarios, negative scenarios and extremes. In other words:<br />
<ul>
<li>What if the data is exactly what we planned for -- records with all the right data in all the right places?</li>
<li>What if the data falls outside of expected norms -- records with missing fields or invalid data, for example?</li>
<li>What if the data is coming in from a data import operation or an integration and many records need to be processed?</li>
</ul>
Admins can follow a few simple steps to create automated tests to run against their configuration changes, and their efforts can be used by developers for better unit tests as well. Simply create sample data representative of the expected inputs. Then use code like the following to load that data in a unit test:<br />
<br />
<script src="https://gist.github.com/snugsfbay/f6419653c9a82e287ffa1f842614eb4d.js"></script><br />
Note that you will want to use data that corresponds to the configuration changes that you are testing. In this example, configuration changes and business process automation around Account, Contact and Opportunity record creation will be tested. You can create a similar test class for other related objects, including custom objects.<br />
<br />
This code can be run as a unit test by itself to validate configuration changes, or it can be called by other test code to set up data for more complex unit testing related to other code in the org.<br />
<br />
Next week, I will look into some of the errors that might occur when you create CSV files of sample data and how to avoid those errors.<br />
<br />
But for now, <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> has a point, who wants Superman looking at just any old thing with his x-ray vision when he ought to be focusing on information that's most helpful.<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com1tag:blogger.com,1999:blog-4433114952640539478.post-91114542390862742762016-07-11T13:57:00.001-07:002016-07-15T07:40:05.607-07:00Enough Is As Good As A Feast<a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> loves Sir Thomas Mallory and Mary Poppins, and quotes both when she reminds us "enough is as good as a feast", especially when Tim Toady's eyes are bigger than his stomach at the buffet. So I thought I would look at Salesforce storage limits to see if we have a feast in our Enterprise Edition org (which is the entry-level org for many businesses and the basis for the nonprofit license grant, even those with the nonprofit starter pack pre-installed).<br />
<br />
Salesforce currently allocates 20MB of data storage per user in every EE org. But wait, there's more. Every org starts with a minimum of 1GB of data storage. So whether you are a nonprofit with a grant of 10 free licenses or a small business with 50 licenses, you have a minimum of 1GB for data.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmm1Lj8TOKFHOOnk46_3WVwkBNdLAX16cJBJuVQqAKYhlJgfat1ESecpaP0W01AHufgPx7nEc_getqBe5N51Ri6gWx0SC5tZqqBwkYgHNvNvbYOSAXjeZpg3RsjtCvZdMBMSR6dzqpBdzC/s1600/manspread.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmm1Lj8TOKFHOOnk46_3WVwkBNdLAX16cJBJuVQqAKYhlJgfat1ESecpaP0W01AHufgPx7nEc_getqBe5N51Ri6gWx0SC5tZqqBwkYgHNvNvbYOSAXjeZpg3RsjtCvZdMBMSR6dzqpBdzC/s320/manspread.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">More than enough is too much.</td></tr>
</tbody></table>
But how many records is that? Salesforce allocates 2KB for most records. Articles require 4KB, Campaigns require a whopping 8KB (4 times the size of most other records). That means a basic Salesforce org (Enterprise Edition or better) will have data storage capacity for about 500,000 records (excluding Campaigns and Articles). If you have 100,000 Accounts and 400,000 Contacts for 1-50 users, you are going to need more storage.<br />
<br />
If you are using Person Accounts, or if you create a unique Account for each Contact, 250,000 individuals would result in 500,000 records since each individual would require both an Account and Contact record.<br />
<br />
Custom objects behave the same as typical standard objects taking 2KB per record, regardless of the number or type of fields associated with those records. Even if you use a lot of rich text fields with large image files, a custom object record still requires only 2KB of data storage. The trick with rich text fields is that they actually are stored as files and so impact file storage rather than data storage.<br />
<br />
Consider your storage needs carefully when you create sandboxes. Partial Copy sandboxes currently provide 5GB of data storage, that's more than you have in your production org if you have 50 or fewer users! But they don't offer much in terms of file storage. You may need a Full Copy sandbox for the convenience of copying all of your data at once and accommodating larger amounts of file storage and files from rich text fields.<br />
<br />
But for standard data needs, use these basic formulas to calculate your data needs in GB:<br />
<br />
<div style="text-align: center;">
( <i># of records</i> <b>X</b> 2KB ) <b>X </b>1/1024 <b>X </b>1/1024</div>
<div style="text-align: center;">
or</div>
<div style="text-align: center;">
( <i># of Campaigns </i><b>X </b>8KB ) <b>X </b>1/1024 <b>X </b>1/1024</div>
<div style="text-align: center;">
or</div>
<div style="text-align: center;">
( <i># of Articles</i><b> X </b>4KB ) <b>X </b>1/1024 <b>X </b>1/1024</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
In the first formula, we multiply the number of records you have times 2KB, the data storage typically needed for records to get the required number of kilobytes of storage. Then we multiply by 1/1024 to convert from kilobytes to megabytes and again to convert from megabytes to gigabytes.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
In the second formula, we multiple the number of Campaign records times 8KB because they consume a lot of storage compared to typical standard and custom objects. Then we do the same calculations to convert from KB to GB as described above.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The third formula is for calculating the storage needs of Articles since their records require 4KB rather than the standard 2KB. Otherwise it works like the first two, with the result expressed in gigabytes.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Keep in mind that Person Accounts and 1x1 Contact to Account data models will create a Contact and an Account record, so every individual is represented by <i>two </i>records rather than just one.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Salesforce offers options for purchasing additional storage space. You can also upgrade to Performance, Unlimited or similar Editions that offer six times as much data storage per user compared to Enterprise Edition (orgs with fewer than 10 licenses may not see the benefits of the additional storage).</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
But, as <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> would say, it is good to be grateful for what you have and know when you've got enough for your share. Salesforce makes it easy to calculate your needs.</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-73988153522809191702016-06-11T09:57:00.001-07:002016-10-02T17:57:39.143-07:00More Better BotsYou know <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> loves <a href="http://www.snugsfbay.com/2016/03/static-v-instance-or-how-can-variable.html">Jeopardy!</a>, the tv show with all the answers, but we have an old friend named <a href="http://nlp-addiction.com/eliza/">Eliza</a> who believes we can find all the answers we need by asking ourselves the right questions. My developers have been asking some of the right questions since their recent trip to the TrailheaDX conference (a conference for Salesforce Developers, similar to past <a href="http://blogs.adobe.com/flex/2007/06/learn_more_about_flex_and_sale.html">conferences in 2007</a> and 2010).<br />
<div>
<br /></div>
<div>
First of all, the developers asked what we should do about all of our existing Visualforce pages now that users are craving Lightning Experience. "What can we do to give them that look and feel without a wholesale rewrite of our UI?" they asked. Their questions naturally led them to the answer that we should start simply with applying the <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwig767hqaDNAhVG8WMKHcOUDTYQFggeMAA&url=https%3A%2F%2Fwww.lightningdesignsystem.com%2F&usg=AFQjCNFUf2E0tMl7mvbWvpOKiDWzS9GvVQ&sig2=bevM0-NvjMKL_nUb6yCeuw">Lightning Design System</a> to what we have in Visualforce, as a first step.</div>
<div>
<br /></div>
<div>
Next, the developers asked what was going on with Salesforce and AI. "What's the deal with bots?" they wondered. While they mulled this over, I reached out to Eliza to see what she had to say:</div>
<div>
<blockquote class="tr_bq">
> Hello. My name is Eliza. How may I help you?<br />
* Eliza, what's the difference between AI and machine
learning?<br />
> Ahh. Please
continue...<br />
* Really, I have three issues: Artificial Intelligence,
Machine Learning and Natural Language Processing.<br />
> What does that suggest to you?<br />
* Like Steve Wozniak said at TrailheaDX, Artificial
Intelligence is nothing without Machine Learning. Natural Language Processing benefits from the
ability to learn better responses.<br />
> I'm not sure I understand you fully.<br />
* Well, GA Tech has done some cool stuff with bots. One learned to answer frequently asked
questions for students.<br />
> Can you elaborate on that?<br />
* For a class that prompted over 10,000 online questions per semester, the professor used Machine Learning and trained a bot using questions and answers from previous semesters. The bot was set to respond to those familiar, frequently asked questions and to only respond to new questions if it calculated a 97 percent or higher confidence level for its answer.<br />
> What does that suggest to you?<br />
* It suggests that I can blend Natural Language Processing and Machine Learning to provide automated, interactive responses to FAQs.<br />
> Say, do you have any psychological problems?<br />
* Um, I do sometimes chat with bots.</blockquote>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
Having a bot that can help customer service agents provide the best responses to Cases would help our service team reply quickly and consistently. We also might want a bot to help provide strategies for the sales team, following the department's best practices. Bots, with the ability to learn from our org's data and best practices can also help us guide new employees and reduce their frustration.</div>
<div class="MsoNormal">
<br /></div>
</div>
<div>
Auntie Pat Tern doesn't really like the term "Artificial Intelligence" because she believes that using code to process our human questions and requests is genuine intelligence. And our old friend Eliza is curious to know how you feel about that.</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-83325277438612951852016-05-17T16:45:00.001-07:002016-05-17T16:45:33.569-07:00SeeAllData = FailAccording to <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a>, it takes 21 days to break a bad habit, but Salesforce developers have had about that many API versions to break the bad habit of writing unit tests with "SeeAllData=true".<br />
<br />
In most cases, this clause alone can render tests completely useless. Unit tests should prove that code functions according to specifications by asserting proper database manipulations--create, read, update, delete operations--as well as Visualforce navigation. <br />
<br />
I looked at unit tests in my org and found this example of a test that failed to achieve its purpose:<br />
<br />
<script src="https://gist.github.com/snugsfbay/50f7b44294861730af51d7dc09e2144a.js"></script>
This test should be asserting that the data for ordering samples can be created with just a contact and sample type defined. Unfortunately the test relies on existing, live, org data rather than test 'silo' data because of "SeeAllData=true" in the first line. There are easy methods for unit tests to create their own test data without relying on live org data.<br />
<br />
We encountered the following problems because of using "SeeAllData=true":<br />
<ul>
<li>It required us to maintain test data among our real data.</li>
<li>When the test data was changed during data cleanup (in one case, Pat Tern's Account was deleted), the tests failed even though functionality was unchanged.</li>
<li>Tests were not reliable between Sandboxes and Production orgs due to data differences rather than actual functionality.</li>
<li>Apex Hammer Tests may not have been automatically monitored in our org for each Salesforce release since Hammer Tests are blind to live org data.</li>
</ul>
In the rare case where a specific piece of data may be required for your code to behave, consider using custom metadata types instead of Salesforce objects. <a href="https://developer.salesforce.com/blogs/engineering/2015/05/testing-custom-metadata-types.html">Trailhead can help you learn more</a> about how they allow you to move metadata and records between orgs and test functionality without needing to see all data in the org.<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-52830481203411698722016-05-07T13:04:00.000-07:002016-05-07T13:04:29.498-07:00Pay Down That Technical Debt<a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> says we should pay with cash, or at least pay our credit cards off every month because "debt," she says, "is like fresh fish, it seems great at first but gets old fast and then it really stinks." <br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAv60ZDoTovN7FC6UY5a6EeCmJXo47-G_g1aNq-hLOiHkK39r0RdPNtNcRMO5Sc8GYkf_J5VMd6CigsMd0XOnfEv2K3EIpg50OQDsucSqeBuJNZP23jn434DPCEW1kbz_3E28-Fy3S4bK_/s1600/hammer.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAv60ZDoTovN7FC6UY5a6EeCmJXo47-G_g1aNq-hLOiHkK39r0RdPNtNcRMO5Sc8GYkf_J5VMd6CigsMd0XOnfEv2K3EIpg50OQDsucSqeBuJNZP23jn434DPCEW1kbz_3E28-Fy3S4bK_/s320/hammer.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">It's Hammer Time!</td></tr>
</tbody></table>
So I looked at my Salesforce org to assess the level of technical debt we had accrued and to plan how we would start paying down that debt.<br />
<br />
Sometimes technical debt comprises the shortcuts or mistakes that no one has time to correct when a project needs to be completed. Technical debt also develops over time. As businesses mature and change, their technical solutions can fall behind and create technical debt.<br />
<br />
A Salesforce org can be especially prone to this since Salesforce offers a wealth of new features for all orgs three times each year and not all companies make an effort to rewrite their technical solutions based on these new features. Luckily, Salesforce offers some tools to help us assess some of the technical debt associated with our code.<br />
<br />
First, I checked our Hammer Test Status. The data silo gauge revealed that we still had old (and sadly a few new) unit tests that were using "seealldata=true", which we needed to update. It also revealed a couple of tests that were failing and so needed some attention.<br />
<br />
Next I checked the API version on our Apex Classes. Any class that is 10 or more versions behind the current API version needed a review, both on the code side and on the process side.<br />
<br />
The third step for me was reviewing our org's documentation for outdated information on our code.<br />
<br />
My org review also included configuration, managed packages and basic processes, as well.<br />
<br />
We may not be able to pay down all of our technical debt right away, but a monthly review and reminder of how it accumulates will help us develop better in the future. And as <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> says, "It's not just <i>pay me now or pay me later</i>, you know. It's<i> pay me now or pay me later with additional compounded interest!</i>"Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-13104082299312262722016-04-10T10:00:00.000-07:002016-04-10T12:05:58.142-07:00Putting Governor Limits To The TestMy <a href="https://twitter.com/AuntiePatTern">Auntie Pat Tern</a> is pretty accepting of cousin Tim Toady's behavior. "He's a teenager, after all, there's no better time for him to test his limits," she explained. So I decided to ask my developers to test their limits in Salesforce.<br />
<br />
<div style="text-align: right;">
</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj23TfLcLwI9mz96K_fFF6pt5V00l426TgnC1codhaYGjDgTEQhQ44VpESfN20quLUByi8-TJ64rOUOswQFwPOUkWAuxU5wWScrSgDLLR0JqFACKnOeFhJde-Hl_I5qbti4m554frJgLMks/s1600/MDLimits2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj23TfLcLwI9mz96K_fFF6pt5V00l426TgnC1codhaYGjDgTEQhQ44VpESfN20quLUByi8-TJ64rOUOswQFwPOUkWAuxU5wWScrSgDLLR0JqFACKnOeFhJde-Hl_I5qbti4m554frJgLMks/s320/MDLimits2.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8px;">One Master object with 13 Detail objects, </span><br />
<span style="font-size: 12.8px;">some of which are Masters in other relationships as well.</span></td></tr>
</tbody></table>
I wanted them to see for themselves how governor limits benefit the overall performance of the code they write. And I wanted them to experiment with ways to push those limits by trying to break things.<br />
<br />
They built Processes, wrote triggers, and configured some unwieldy objects that I would never want to see in production all in an effort to push good performance to the very edge of being bad.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCAiLNXCOvkV0VSNpgKZ6HUHpZ_2kSk4SWRWjS5YR2AgzSA-j_4kqhr8DitGf-DHnyd8vyOBrNFhLsOFq1-XevecXBkXb1mOOmM5F2ZMWSMoOCsRcg3rMJ37ImCZ3NRC_-JeWTF47M4nTm/s1600/MDLimits.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCAiLNXCOvkV0VSNpgKZ6HUHpZ_2kSk4SWRWjS5YR2AgzSA-j_4kqhr8DitGf-DHnyd8vyOBrNFhLsOFq1-XevecXBkXb1mOOmM5F2ZMWSMoOCsRcg3rMJ37ImCZ3NRC_-JeWTF47M4nTm/s320/MDLimits.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Some limits include object relationships.</td></tr>
</tbody></table>
A couple of these experiments proved that what they understood about limits was untrue. In one example, when it comes to Master-Detail relationships on custom objects, the documentation described a limit of 2^3. Firstly, 2^3 does not equal 8 here. Instead, it indicates that an object can have two M-D relationships and those can be three levels deep.<br />
<br />
Take the example Parent <-- Child <-- GrandChild <-- GreatGrandChild where all relationships are Master <-- Detail. Some of the limits on this relationship structure are as follows:<br />
<br />
<ul>
<li>Parent cannot have a new Master (eg GrandParent) because of the limit on how deep the relationship levels can be. </li>
<li>GreatGrandChild does not show up as available to be a Master in other relationships because we are limited to three levels deep.</li>
<li>Child cannot have a new Master because it already has two M <-- D relationships (even though only one of those points to a Master).</li>
<li>Child can have new Details, that is, new GrandChild-level <i>objects</i> can be created as Details for Child even though Child already has two M <-- D relationships.</li>
<li>Many Child-level <i>objects</i> can be created as Details for Parent (we stopped at over 50). </li>
<li>A Child-level <i>object</i> cannot be used as a junction object between records of a single Parent-level <i>object</i>. M <-- D relationships cannot be immediately self referencing like that.</li>
<li>GrandChild-level and GreatGrandChild-level <i>objects </i>can have the same Master <i>object </i>as their Master, eg. GrandChild can point to Child and Parent as Masters even when Child already points to Parent as its Master. We daisy-chained six objects this way before hitting limits on the depth of the relationships.</li>
<li>Child-level <i>objects</i> with two relationships pointing to Master <i>objects</i> cannot be Masters to new GrandChild-level <i>objects</i>. An object can have two Masters or it can have one Master and many Detail relationships or it can have no Master and many Detail relationships.</li>
</ul>
<br />
It was a fun exercise and demonstrated how limits benefit performance and how hard some of them can be to break. It gave the developers a chance to challenge their assumptions, be creative and gain a better understanding of the implications of limits when it comes to writing better code.<br />
<br />
Secretly, Auntie Pattern believes that testing limits can help us appreciate why limits are important, but she wouldn't tell Tim Toady that.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-26579360802944464912016-04-03T10:20:00.000-07:002016-04-25T16:44:09.829-07:00Painless Removal Of Boat AnchorsI asked my <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> why she has a tattoo of a boat anchor on her forearm and she said, "Boat anchors symbolize hope, but I'm considering getting this one removed." So she didn't have it to enhance her resemblance to Popeye like cousin Tim Toady always says.<br />
<br />
It may have been hope that also inspired the boat anchor I found in the code in my org. In technical circles, some people only think of boat anchors as that outside technology they got stuck with because their boss bought it without conducting a technical review. But if you aren't constantly conducting a technical review of your own code, you can get stuck with boat anchors there as well.<br />
<br />
In my org, I found something like the following:<br />
<br />
<script src="https://gist.github.com/snugsfbay/35d6c9cdf5cb8b0b9ab508798692eda7.js"></script>
All code that had once handled business logic was commented out to the point where the code literally did nothing but returned a null value. I think this boat anchor represented the developer's hope that the original code might somehow be useful later. If that's the hope, the code can be stored outside of our production org.<br />
<br />
To remove it, we just needed to correct any references and delete the class and its related unit test. Salesforce offers multiple ways to accomplish this using the IDE, the developer Workbench or the Migration Tool, all of which are much less painful than Auntie Pat Tern's tattoo removal.<br />
<br />
With Workbench, for example, you can simply mark a class or trigger as deleted or as inactive to remove it from production using the following steps after downloading the class or trigger files:<br />
<ol>
<li>Edit the XML meta file for the class or trigger to change its status from <status>Active</status> to <status>Deleted</status> (for classes) or <status>Inactive</status> (for triggers)</li>
<li>Put the both the .XML file and class or trigger file into a folder named "classes".</li>
<li>Create a package.xml file to list the class or trigger to be deleted or made inactive.</li>
<li>Place both the package.xml file and the classes folder into another folder inside a zip file.</li>
<li>Specify this zip file after you select Migration>Deploy in Workbench.</li>
</ol>
A great way to generate a <a href="https://gist.github.com/snugsfbay/28176efcf2370c00abd7#file-package-xml">package.xml</a> file to get you started is to use Setup>Create>Packages in Salesforce and add the classes or triggers that need to be deactivated or deleted. This package can then be specified for download in Workbench using Migration>Retrieve. The zip file will need to be changed as described above to deploy. (For step-by-step instructions, <a href="https://drive.google.com/open?id=0B9HduBZJMbH2S3FjTVFhd3RNZzA">click here</a>.)<br />
<br />
Like Auntie Pat Tern, be on the lookout for boat anchors and consider removing them when they pop up during your org's ongoing technical review. Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com1tag:blogger.com,1999:blog-4433114952640539478.post-31679066322041719692016-03-11T12:39:00.000-08:002016-06-03T08:47:47.900-07:00Static V. Instance, or, How Can A Variable Be Unchanging?I asked my <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> why she loves to watch Jeopardy! and she said, "if I watch it enough, I will see answers to all the questions in the world." So I looked through the questions that my developers ask to see if they could be answered by Jeopardy!<br />
<div>
<br /></div>
<div>
One of the questions that comes up frequently is whether use of the 'static' keyword is an antipattern or whether it is best practice. Of course, if it's used wrong, it is an antipattern, so understanding static versus instance methods, variables and initialization code is important.</div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl8R-M1l0xXZZUGdqX9HBpai6pI7A12XatHfRUm9L5j2YIBOi-DjAbBHlIZsS23HZC6oTiLB76WtbHExrVA_1T4bDA7sjqX6z_r3nVBfi3gbK-L5dA_uA3stVl2R_Foynisi4Za_t4cP_C/s1600/constant.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl8R-M1l0xXZZUGdqX9HBpai6pI7A12XatHfRUm9L5j2YIBOi-DjAbBHlIZsS23HZC6oTiLB76WtbHExrVA_1T4bDA7sjqX6z_r3nVBfi3gbK-L5dA_uA3stVl2R_Foynisi4Za_t4cP_C/s1600/constant.jpg" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Final Jeopardy! means there won't be <br />
infinite answers this time.</td></tr>
</tbody></table>
<br /></div>
<div>
Taking Jeopardy! as our example, the classic game show that contestants win by providing the most correct responses, we can see that some things don't change from week to week. The show's name, the show's host, these are constants and so of course are static because "static" means unchanging. A static response can be provided for questions about the host and show name.</div>
<div>
<br /></div>
<div>
Every show has three contestants and to create a show, its producers need to know who the three contestants will be. So they conduct tryouts to choose and schedule competitors. The names of the competitors change from night to night, so the list of competitors is variable, but show producers have to know who is scheduled before the show is created, so it is a static variable. A static response can be provided to the question of who will be the competitors for any specified date.</div>
<div>
<br /></div>
<div>
When the show is filmed, the responses that one contestant provides as part of the action of the show are defined by the instance of the show and depend on the inputs the contestant receives from the show and the interactions the contestant has with other contestants on that particular show. So these responses are non-static and depend on the instance of the show.</div>
<div>
<br /></div>
<div>
As an example let's consider three possible questions about the upcoming Jeopardy! college championship round:</div>
<div>
<ol>
<li>Who's the host? We expect one answer: 'Alex Trebek'. </li>
<li>Who are the competitors? We expect one answer: the three college students, depending on who is chosen for a specified day. </li>
<li>What is the contestant's 'question' and score for the first input in the first category? The response to this question depends on actually seeing the college championship round in action, knowing what the inputs are and seeing which contestant acts first and the result of that particular action. </li>
</ol>
</div>
<div>
So the first two are static and the last one non-static and specific to its instance. </div>
<div>
<br /></div>
<div>
In Apex, you can see an example of static vs. instance in the Date class. This class offers both static and instance methods. Let's consider three possible questions we could ask today:</div>
<div>
<ol>
<li>What is the date today? We expect one specific answer for this question and it doesn't need any additional information for us to ask it: Date.today().</li>
<li>Is it a leap year? We expect only one answer for this question, depending on a specified year, for example: <i>Date.isLeapYear(2016);</i> or <i>Date.isLeapYear(2023);</i>.</li>
<li>What is the year? The response depends on knowing the date in question -- we need an <i>instance</i> of Date in order to figure out the year of that specific date, for example: <i>Date yearLater = Date.today().addYears(1); Integer nextYear = yearLater.year();</i>.</li>
</ol>
</div>
<div>
Again, the first two are static methods while the third, determining the year, is specific to its instance. You might wonder, for example, what happens in Apex when you add a year to a leap day, will Apex give us February 28 or March 1 of the next year (or null)? You could run the following code to create an instance specific to a leap day and test it out:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/snugsfbay/35956690c357816198ea.js"></script>
</div>
<div>
The above code primarily uses instance methods, but using the 'static' keyword in Apex can be particularly useful when it comes to writing code called by Triggers. Since a single Trigger can result in a cascade of other Triggers firing, we may need to keep track of some information across all the business process automation associated with the cascade of Triggers. Having a separate class with a static method or variable for all of the Triggers allows us to share specific data across the code executing for multiple Triggers.<br />
<br />
For example, a separate class that contains a static variable can indicate the number of times a particular automation has run to help avoid an <a href="https://help.salesforce.com/apex/HTViewSolution?id=000133752&language=en_US" target="_blank">infinite recursion</a>. </div>
<div>
<br /></div>
<div>
Infinite recursions need to be avoided in code, but <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> may be correct that infinite episodes of Jeopardy! will contain all the answers to all the questions in the world.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-48981230197816381212016-03-04T11:41:00.001-08:002016-03-05T09:13:27.601-08:00Start Documenting Rather Than Accepting "No Comment"My <a href="https://twitter.com/auntiepattern" target="_blank">Auntie Pat Tern</a> tried to convince my cousin Tim Toady that he should be using the 3/5 rule of essay writing he'd been taught -- three ideas, five paragraphs -- but, as usual, Tim insisted there is more than one way to do it (TIMTOWTDI). So I looked through the code in my Salesforce org to see if my developers were following the <b>3/5 rule for comments</b> or if TIMTOWTDI had gotten into our code. Unfortunately, I mostly found code with no comments at all.<br />
<br />
Code without comments is like a research paper without a thesis statement to detail its purpose. It's like doing something over and over without understanding why because comments should always clarify why it does what it does. It's like burying treasure without leaving a proper map because good comments point to valuable resources the code uses or makes available.<br />
<br />
Code comments should follow the 3/5 rule of comments: there are three places where comments should occur and five specific topics that need to be addressed.<br />
<br />
The three places where comments should be found in Apex code are:<br />
<ol>
<li>Block comments at the beginning of classes.</li>
<li>Block comments at the beginning of methods.</li>
<li>Line level comments for constants, loops, conditions, and where clarification is <i>possible</i>.</li>
</ol>
The five topics that should always be found in block comments are:<br />
<ol>
<li>Description of purpose and assumptions.</li>
<li>Author/date for creation and modification.</li>
<li>Parameters for methods that accept values, or none.</li>
<li>Return values for methods that pass values, or none.</li>
<li>References and dependencies.</li>
</ol>
<div>
Here's an example of code that follows the 3/5 rule of comments:</div>
<div>
<br /></div>
<script src="https://gist.github.com/snugsfbay/35ae0298cfb750175624.js"></script>
<br />
<div>
<br /></div>
<div>
In this example, block comments appear at the start of the class and at the start of the methods while inline comments appear within methods and for named constants. The comments use Javadoc tags like "@description" to make the important topics easy to locate. These comments even include "TBD" to indicate code that is incomplete and point out the limitation imposed by the choice of Integer as a data type rather than Long. Comments should always include information that may be reconsidered during the next phase of development.<br />
<br />
We ask that developers and admins both be responsible for code comments because the admin should know how code effects data integrity and user experience. Without that level of cooperation and understanding, admins have been known to implement validation rules that cause code to fail and developers have been known to implement code that causes user experience to decline.</div>
<div>
<br /></div>
<div>
Tim Toady is right, there is more than one way to do it with code. That's why we ask for comments that explain why the code was written the way it was. And we follow Auntie Pat Tern's 3/5 rule to make sure we have comments in three areas of code and covering 5 required topics. Better comments lead to better collaboration and easier maintenance of the code and the org where it runs.</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com3tag:blogger.com,1999:blog-4433114952640539478.post-37286286391752645292016-02-24T09:07:00.001-08:002016-03-05T09:22:59.012-08:00Using Trailhead To Resolve Unknown UnknownsAccording to my <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a>, the only trouble with my cousin Tim Toady is that "like every teenager, he don't know what he don't know. And that wouldn't be so bad if his teachers were better at knowing what he don't know." So I took a look at the code in my org to see if I could pinpoint what it is that the developers don't know.<br />
<br />
Luckily, the <a href="http://www.snugsfbay.com/2015/08/salesforce-nurtures-creativity-passion.html" target="_blank">Trailhead team</a> is great at foreseeing what it is that people don't know about Salesforce and have created a Trail for that, no matter what that is. And while the developers might find the Apex trails on their own, they might not recognize that there is more about Salesforce they need to understand. In fact, there is an entire Trail on the <a href="https://developer.salesforce.com/trailhead/trail/salesforce_advantage" target="_blank">Salesforce Advantage</a>, the core technology that differentiates Salesforce from other CRM systems and other development platforms.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgstnVEyOccWvKm2yq7smG765b7k1Ni6FzRU-FqDboOjpxaB_50nViuzmqpYYw6NbPLP7tCIREiZVLkb5_uXltwyYY18v_P1ahNseO3DA2g73JZGycidPkJfDy5kPS8b2j4tt84VjuF1YA3/s1600/trailhead_module_advantage_salesforce_technology_basics.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgstnVEyOccWvKm2yq7smG765b7k1Ni6FzRU-FqDboOjpxaB_50nViuzmqpYYw6NbPLP7tCIREiZVLkb5_uXltwyYY18v_P1ahNseO3DA2g73JZGycidPkJfDy5kPS8b2j4tt84VjuF1YA3/s400/trailhead_module_advantage_salesforce_technology_basics.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Learn, or review, Salesforce Technology Basics<br />
with the new Trailhead module.</td></tr>
</tbody></table>
One developer expressed concerns about "the Governor's limits", which indicates to me that they need to better understand multitenancy and performance. Another expressed concern about Salesforce firewalls and security breaches, which indicates they need to learn about Salesforce security standards. A third developer suggested we build custom objects for storing employee contact data and build content management and customer service solutions from scratch, which meant they need to learn more about fast app development with Salesforce customizations and third-party apps.<br />
<br />
Happily, Salesforce has a new Trailhead module to help my group know more about all these topics, <a href="https://developer.salesforce.com/trailhead/module/salesforce_advantange_how_we_do_it" target="_blank">Salesforce Technology Basics</a>. Of course my developers are a lot like my cousin Tim Toady, they know they are a smart bunch but they often don't realize that there are things they don't know. It's the Dunning-Kruger Effect, the unknown unknowns.<br />
<br />
For those who are deeply familiar with Salesforce, Trailhead can help you avoid the "curse of knowledge" tendency to believe that if you know it then most people must know it as well. Trailhead modules are thorough, starting with the basics and moving to more challenging information. And they are entertaining, so anyone with a smattering of knowledge will find familiar topics fun to review and new topics informative. <br />
<br />
With Trailhead, you can avoid the problem Auntie Pat Tern described for cousin Tim Toady, the unknown unknowns as well as the curse of knowledge. Just encourage your team to earn Trailhead badges, which you can review in their Salesforce Community Profile pages, to bring the team up to speed even when you, or they, think they know what they need to know already.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-38446047811695715092016-02-21T12:08:00.001-08:002016-02-21T12:11:27.359-08:00Code Smell Leads To Improved Interprocess CommunicationsMy <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> said she always knows when her teenage kids have guests over and her friend wondered how. Is it the noise, the mess, the smell? "No," said Auntie Pat Tern, "I just ask them and they tell me." So I thought I would look through the code in my org and pass this straight-forward idea for communication on to my developers.<br />
<div>
<br />
When code review uncovers a lot of small problems, this can often bring larger problems to the surface. "Code Smell" refers to small problems that may reveal bigger concerns in code. I previously gave an example of code that uses a <a href="http://www.snugsfbay.com/2016/02/poltergeist-busters-get-call.html" target="_blank">'poltergeist' object</a> to pass data from an external system into a custom Salesforce object before creating the data in the required Salesforce object. The same code also uses <a href="http://www.snugsfbay.com/2016/02/my-auntie-pat-tern-recently-borrowed.html" target="_blank">'hard coded' values</a> that are not named constants. And that "Code Smell" reveals the use of a database field for interprocess communications, setting a field value to 'success' when the record is created rather than relying on more direct means of communication.
<br />
<br />
<script src="https://gist.github.com/snugsfbay/824732687ed2d017d242.js"></script>
<br />
Using the Apex Database class, as shown in the second code block, provides a direct means of communication that would make <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> proud.
</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-6296567837901936982016-02-14T15:39:00.000-08:002016-02-14T15:39:59.723-08:00Poltergeist Busters Get A Call<a href="https://twitter.com/auntiepattern" target="_blank">Auntie Pat Tern</a> mentioned that she loves a good ghost story, so I looked through my code and told her about the Poltergeist object I found there.<br />
<br />
Poltergeist objects exist simply for the purpose of passing data from one place to another and are essentially useless. These objects don't serve a clear function relative to business or technology rules, instead they just take up space. Poltergeists are unlike Leads, which are required by business rules to hold data until it can be verified and converted to Contacts. Leads aren't Poltergeists because they service the business rules related to data verification.<br />
<br />
The object I found in my code was no Lead, it was a troublesome Poltergeist.
<br />
<script src="https://gist.github.com/snugsfbay/1ef4be334c7677025ce1.js"></script>
In the above code, the Order object serves no purpose other than passing data from an external system into Salesforce. Since there is no verification process defined, there doesn't need to be a holding bin for data, and it could be passed directly into the Sales Order object that already existed in our Salesforce org. We can simply refactor the code to write directly to the third-party object rather than the Poltergeist.
<br />
<br />
<a href="https://twitter.com/auntiepattern" target="_blank">Auntie Pat Tern</a> said she's seen a lot of weird stuff, but the code in my org might be the scariest of all.<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-47787592224081573722016-02-11T12:44:00.001-08:002016-02-11T13:01:08.833-08:00When To Soft Code Or Not To Soft CodeMy <a href="https://twitter.com/auntiepattern" target="_blank">Auntie Pat Tern</a> got mad at my no good cousin when he told her he changes phone numbers every time he gets a new burner phone; she warned us to make sure we do business by the rules. So I looked through my code and shared her suggestion with my developers. <br />
<br />
It turns out they tried to correct a problem with badly implemented hard-coded values by soft-coding some values that represented software architecture decisions and similar business rules.<br />
<br />
Previously, I showed you the <a href="http://www.snugsfbay.com/2016/02/my-auntie-pat-tern-recently-borrowed.html" target="_blank">example of a hard-coded username</a> being assigned as record owner, which caused two problems in the org. The first problem was that the username needed to be an API-only user rather than an employee who might leave the company whose username would be deactivated. The second problem was that the username was hard-coded deep in the code rather than being represented as a constant at the beginning of the class.<br />
<br />
The developer who tried to fix these problems decided to soft-code the username as follows:<br />
<br />
<script src="https://gist.github.com/snugsfbay/3e01b41dc22936b79ed4.js"></script>
Using Custom Settings allows the username to be changed outside of code at any time, multiple times. The above example does not solve the first problem we had, though. Unfortunately, soft-coding the username defeats our business rule requiring data coming from integrations to be owned by a user or Queue specific to that integration. In other words, our business rule required the use of a constant rather than a soft-coded value. <br />
<br />
We had to take that code back to the drawing board one more time because, like <a href="https://twitter.com/auntiepattern" target="_blank">Auntie Pat Tern</a> demonstrates, code should behave according to the rules of business, and enforce those rules automatically.<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-72340818989862732012016-02-08T08:49:00.000-08:002016-02-08T16:40:38.551-08:00Magic Numbers and Hard Coded ValuesMy <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> recently borrowed her friend's phone and noticed the recently called phone numbers didn't have names assigned, so she called everyone to remind them to enter contact names with their phone numbers. I looked through some of the code in my org and decided to share her advice with my developers. I found code that made use of Magic Numbers and hard-coded values, both of which make the code difficult to maintain.<br />
<br />
Imagine Auntie Pat Tern's frustration when she wanted to find a particular number and couldn't because it wasn't listed under any of the names she expected to see. And the contact list was empty. She couldn't find the number she wanted and she couldn't tell what any number was for without a contact list. In programming, the variable and constant declarations are like the contact list and allow us to give understandable names to numbers we use in the code. Numbers that appear without names and descriptions are known as "Magic Numbers" because they appear and seem to work by magic, such as the following example:<br />
<br />
<script src="https://gist.github.com/snugsfbay/812dc390ef4013ed396a.js"></script>
Imagine trying to maintain code like this, would you know where to change a value and how often that value may be repeated in the code for the same use? Does 0.43 need to be changed to 0.435 every time it occurs in this class, or just in a single line of code. These values should be named according to the business logic being automated and should be declared as constants for more readable and maintainable code.<br />
<br />
Magic Numbers aren't the only hard-coded values I found in the code. Deep within the bowels of one utility class I found a user name hard-coded as the owner of all records generated by our integration with another database.<br />
<br />
<script src="https://gist.github.com/snugsfbay/ca87d43177d64396371e.js"></script>
In the example above, you can see the hard-coded user name, but you can't see the fact that this was a real user, and happened to be someone who had left the company and so was deactivated. A better approach for this would be to assign an owner that is an Apex-only user, a bot-user specific to this integration, rather than a real person, and define that user name as a constant. <br />
<br />
Static variables, at the beginning of a class, provide an ideal location for declaring variables and constants associated with business logic. At the beginning of the class, they can be near the class description, the comment that describes the business case being automated by the class, and make maintenance a breeze.<br />
<br />
<script src="https://gist.github.com/snugsfbay/d5d998ca9ccc59355a3c.js"></script>
Naming values and putting them where others expect to find them will help you avoid problems like what happened with my <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a>.<br />
<br />
<br />
<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-7200990326554667362016-02-01T12:40:00.001-08:002016-02-01T12:40:36.202-08:00Avoiding the Negative for Clear CodeMy <a href="https://twitter.com/AuntiePatTern" target="_blank">Auntie Pat Tern</a> recently reminded me to avoid double negatives and use positive language as often as possible. So I looked through some of the code in my org and decided to share her advice with my developers. When we write conditional statements using NOT (or "!"), we are using negative syntax which is more difficult to understand than positive syntax. Here's an example written in negative syntax, then rewritten in positive syntax:<br />
<div>
<br />
<script src="https://gist.github.com/snugsfbay/bc71acfac894d3fa3961.js"></script>
</div>
The conditions evaluate the same, but I find the negative syntax more difficult to read during code review and maintenance. Note that it can be improved upon further with a basic knowledge of <a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_string.htm" target="_blank">String methods</a>. <br />
<br />
The first time I encountered super negative syntax, I thought the developers who used it were making a game of being abstruse. But knowing that the two programmers were friends led me to discover that this was in fact a case of "cargo cult programming" where they were sharing and reusing a bad pattern because they hadn't taken the time to pick apart what the code needed to accomplish. Once they better understood what the code was doing, they learned to write it more clearly.Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0tag:blogger.com,1999:blog-4433114952640539478.post-89222337549826898822015-10-01T05:50:00.002-07:002015-10-01T05:54:50.403-07:00Even Small Companies Benefit From A Center Of Excellence Team<div>
User adoption is a double-edged sword for some companies. As more users become more active on Salesforce, and as more departments find it to be the best solution for their needs, the more work administrators and developers have in keeping the system working the way users need it to work.</div>
<div>
<br /></div>
<div>
I've heard of companies that have such a large backlog of requests in Salesforce that by the time any work request gets cleared, the requesting user may no longer even need whatever they requested. Obviously pulling work requests out of a backlog on a First In First Out basis is not a manageable solution for anything much more complicated than user provisioning and password regeneration.</div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLg8HhMT6ynQQvh_IZFcz5eJiVt7HT9rOuw805EInt_4CqVeJXoafssdiwUxtyVHvAeF_5Sjrc8qD-kiBm5KwNZn31G7Nvm8RuY_wJLK5_HSjzn10r4B6mEUEdyKqaUv3c8ZAhml1NWUR/s1600/happycar.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLg8HhMT6ynQQvh_IZFcz5eJiVt7HT9rOuw805EInt_4CqVeJXoafssdiwUxtyVHvAeF_5Sjrc8qD-kiBm5KwNZn31G7Nvm8RuY_wJLK5_HSjzn10r4B6mEUEdyKqaUv3c8ZAhml1NWUR/s320/happycar.png" width="313" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A governance team can help keep things running smoothly.</td></tr>
</tbody></table>
<br /></div>
<div>
Instead, companies should consider implementing a more mature governance system like a <a href="http://www.slideshare.net/kshermansfdc/salesforce-crm-7-domains-of-success" target="_blank">Center of Excellence (CoE)</a>, or scaled down version in the form of a <a href="http://www.snugsfbay.com/2015/09/build-teams-not-committees.html" target="_blank">Success Team</a>. This governance body for Salesforce orgs brings all the stakeholders to the table at once and provides transparency into the important issues each department is facing.</div>
<div>
<br /></div>
<div>
You may be familiar with scenarios of what happens without a CoE: multiple departments need customization work but the administrators and developers are stretched too thin to dedicate a resource to any project. In some companies, new requests simply spread resources even thinner across yet more work.</div>
<div>
<br /></div>
<div>
For example, the product department needs a way to mass input new products while the customer service department needs a smoother way to handle complex steps for authorizing a product return and credit. The admins and developers are stretched too thin to take on both tasks simultaneously. But that's what they are asked to do any way. And so both projects chug along ever more slowly without the proper attention to detail.</div>
<div>
<br /></div>
<div>
Instead, an active CoE can prioritize these requests based on input from administrator, developer and end-user representatives. But the administrator has to be given a lot of say in the CoE decisions.</div>
<div>
<br /></div>
Special talents of any good Salesforce Administrator include the ability to understand your specific business processes and how they relate to Salesforce features and capabilities. Companies need to use that person's knowledge to put projects in logical order and give them a reasonable timeline. And in some cases, departments may discover that their needs overlap and the administrator can accomplish multiple tasks at once. <br />
<div>
<br />
<h4>
Nightmares of No Governance</h4>
</div>
<div>
One administrator I worked with had multiple departments needing a way to combine records into various related groups. A simple addition to the data model and Heroku Connect settings could have made that possible, but coordinating with three departments for a solution required getting everyone together to discuss. That is the most difficult part of projects without a CoE.<br />
<br />
In this example, the administrator had built out and populated a model that no one was using. The administrator had been working with customer service, but that department had turned its attention to fighting other fires. The product department was at a loss about how even to put a request together for configuration changes in Salesforce and had a terrible relationship with IT. And the marketing department did not know they could simply use Heroku Connect to pull the data they needed from Salesforce into their web app. The administrator and developers didn't even have a way to communicate to users that solutions were complete because they did not have User Acceptance Testing scheduled. <br />
<br />
I've also worked with CIOs who make purchasing decisions based on demos rather than actual product testing in Sandbox. These CIOs expect administrators to configure ill-conceived or undefined solutions with untested products. Yet a CoE can create well defined functional requirements enabling the administrator and select users to conduct basic testing before purchase decisions in order to determine how new packages interact with existing systems and whether they address basic business needs.<br />
<div>
<br />
<h4>
Simple Efficiency of Teamwork</h4>
</div>
<div>
Rather than setting your projects up to fail by not allocating sufficient time to them or setting up your company to fail by pitting departments against each other to fight over limited internal resources, set up a CoE to handle these issues in a transparent way. Discussions can be continued in Chatter and resources can be shared in Content Libraries or Chatter Files for full disclosure to Salesforce users. Proper governance records why decisions were made, which keeps your company from spinning its wheels revisiting decisions when there is no new information.<br />
<br />
The beauty of the CoE is that it can be scaled to meet your company size and needs. Start with an executive sponsor and department managers who are using Salesforce as well as administrator and developer representation. Add a couple of power users and training experts. Schedule meetings and combine them with an online Chatter group to continue any open discussions. You will find that this can help equally with the initial roadmap of Salesforce projects and ongoing collaboration as well.<br />
<br />
When projects require outside vendors, there should be an administrator in all meetings with the vendors to ensure that the business and user needs are well defined for your vendor partner as well as for anyone responsible for in-house support and maintenance after the project goes live.<br />
<br />
Once departments start sharing how they are using Salesforce, they may even inspire each other to make better use of data that is already in the system.</div>
</div>
Anonymoushttp://www.blogger.com/profile/01478082495322024136noreply@blogger.com0