Showing posts with label best practice. Show all posts
Showing posts with label best practice. Show all posts
Wednesday, April 5, 2017
Real Business Data Returns
Auntie Pat Tern 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 static resources for test data. 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:
With this simple trick, I can preload my dev orgs with sample business data that I am using in my unit tests. Like Auntie Pat Tern promised, I can have my cake and eat it too when it comes to using realistic sample data in my tests and development orgs.
Labels:
Apex,
best practice,
CSV,
relationships,
test data,
unit test
Saturday, June 11, 2016
More Better Bots
You know Auntie Pat Tern loves Jeopardy!, the tv show with all the answers, but we have an old friend named Eliza 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 conferences in 2007 and 2010).
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 Lightning Design System to what we have in Visualforce, as a first step.
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:
> Hello. My name is Eliza. How may I help you?
* Eliza, what's the difference between AI and machine learning?
> Ahh. Please continue...
* Really, I have three issues: Artificial Intelligence, Machine Learning and Natural Language Processing.
> What does that suggest to you?
* Like Steve Wozniak said at TrailheaDX, Artificial Intelligence is nothing without Machine Learning. Natural Language Processing benefits from the ability to learn better responses.
> I'm not sure I understand you fully.
* Well, GA Tech has done some cool stuff with bots. One learned to answer frequently asked questions for students.
> Can you elaborate on that?
* 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.
> What does that suggest to you?
* It suggests that I can blend Natural Language Processing and Machine Learning to provide automated, interactive responses to FAQs.
> Say, do you have any psychological problems?
* Um, I do sometimes chat with bots.
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.
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.
Labels:
AI,
artificial intelligence,
best practice,
best practices,
bot,
bots,
Einstein,
Eliza,
LDS,
learn to code,
Lightning,
machine learning,
Salesforce,
salesforce developer conference,
TrailheaDX,
Visualforce
Tuesday, May 17, 2016
SeeAllData = Fail
According to Auntie Pat Tern, 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".
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.
I looked at unit tests in my org and found this example of a test that failed to achieve its purpose:
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.
We encountered the following problems because of using "SeeAllData=true":
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.
I looked at unit tests in my org and found this example of a test that failed to achieve its purpose:
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.
We encountered the following problems because of using "SeeAllData=true":
- It required us to maintain test data among our real data.
- 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.
- Tests were not reliable between Sandboxes and Production orgs due to data differences rather than actual functionality.
- 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.
Friday, March 11, 2016
Static V. Instance, or, How Can A Variable Be Unchanging?
I asked my Auntie Pat Tern 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!
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.
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.
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.
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.
As an example let's consider three possible questions about the upcoming Jeopardy! college championship round:
- Who's the host? We expect one answer: 'Alex Trebek'.
- Who are the competitors? We expect one answer: the three college students, depending on who is chosen for a specified day.
- 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.
So the first two are static and the last one non-static and specific to its instance.
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:
- 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().
- Is it a leap year? We expect only one answer for this question, depending on a specified year, for example: Date.isLeapYear(2016); or Date.isLeapYear(2023);.
- What is the year? The response depends on knowing the date in question -- we need an instance of Date in order to figure out the year of that specific date, for example: Date yearLater = Date.today().addYears(1); Integer nextYear = yearLater.year();.
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:
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.
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 infinite recursion.
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 infinite recursion.
Infinite recursions need to be avoided in code, but Auntie Pat Tern may be correct that infinite episodes of Jeopardy! will contain all the answers to all the questions in the world.
Wednesday, February 24, 2016
Using Trailhead To Resolve Unknown Unknowns
According to my Auntie Pat Tern, 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.
Luckily, the Trailhead team 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 Salesforce Advantage, the core technology that differentiates Salesforce from other CRM systems and other development platforms.
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.
Happily, Salesforce has a new Trailhead module to help my group know more about all these topics, Salesforce Technology Basics. 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.
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.
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.
Luckily, the Trailhead team 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 Salesforce Advantage, the core technology that differentiates Salesforce from other CRM systems and other development platforms.
![]() |
| Learn, or review, Salesforce Technology Basics with the new Trailhead module. |
Happily, Salesforce has a new Trailhead module to help my group know more about all these topics, Salesforce Technology Basics. 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.
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.
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.
Sunday, February 21, 2016
Code Smell Leads To Improved Interprocess Communications
My Auntie Pat Tern 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.
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 'poltergeist' object 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 'hard coded' values 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.
Using the Apex Database class, as shown in the second code block, provides a direct means of communication that would make Auntie Pat Tern proud.
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 'poltergeist' object 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 'hard coded' values 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.
Using the Apex Database class, as shown in the second code block, provides a direct means of communication that would make Auntie Pat Tern proud.
Sunday, February 14, 2016
Poltergeist Busters Get A Call
Auntie Pat Tern mentioned that she loves a good ghost story, so I looked through my code and told her about the Poltergeist object I found there.
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.
The object I found in my code was no Lead, it was a troublesome Poltergeist.
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.
Auntie Pat Tern said she's seen a lot of weird stuff, but the code in my org might be the scariest of all.
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.
The object I found in my code was no Lead, it was a troublesome Poltergeist.
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.
Auntie Pat Tern said she's seen a lot of weird stuff, but the code in my org might be the scariest of all.
Thursday, February 11, 2016
When To Soft Code Or Not To Soft Code
My Auntie Pat Tern 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.
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.
Previously, I showed you the example of a hard-coded username 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.
The developer who tried to fix these problems decided to soft-code the username as follows:
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.
We had to take that code back to the drawing board one more time because, like Auntie Pat Tern demonstrates, code should behave according to the rules of business, and enforce those rules automatically.
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.
Previously, I showed you the example of a hard-coded username 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.
The developer who tried to fix these problems decided to soft-code the username as follows:
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.
We had to take that code back to the drawing board one more time because, like Auntie Pat Tern demonstrates, code should behave according to the rules of business, and enforce those rules automatically.
Subscribe to:
Comments (Atom)

