Comments (5)
Ok, its a thought, given there should be just one commitWork in a request context, i'm considering what portion of this process really consumes compared to the overall execution of the request and the work it doing (querying, doing apex, other trigger code etc). Its always good to be a bit quantitate in doing these type of optimisations, which i know is a little hard on the platform, but the Limits class does permit access to heap and cpu time, so i'd be interested in some comparisons between a base line use case with a full application class and say a stripped down version with a test application class just for that request to get a feel for the variance. As adding extra processing to the register methods overall could have a more detrimental effect. So yeah, i get the idea, just think some profiling is warranted to help give more confidence around such a change. Make sense?
from fflib-apex-common.
Makes perfect sense and completely agree! Based on your suggestion, I created some test cases/scenarios around the concepts. In order to truly get a feel for the difference, I created a customized UOW that approached things the way I described in the OP. Running tests against just larger and smaller Application classes wouldn't really give us a true sense of what the change would mean CPU/Heap/etc. wise, only what having more/less classes does to the current approach.
The tests are very unscientific of course and are focused on pure DML operations not necessarily the relative percentage of an overall transaction that would go through a typical service layer. To your point, if the "DML" is just 5% of an overall transaction and making a change like this means improving the "DML" by 50% but the overall by only 1% (assuming a typical transaction), it might not be worth the investment.
With all that said, here are the two baselines:
- Existing fflib UOW
- Modified fflib (using Integer Maps) as described in OP
Test Case Process - Goal here is to mirror a typical UOW usage which I'm guessing normally includes approximately 5-6 records
- Create a set of records
- Start Test
- Log Limits
- Insert 3 new records using UOW
- Update 3 records (from #1) using UOW
- commitWork
- LogLimits
The results were fairly interesting:
- UOW with 1 Class
Current: Heap 5887 / CPU 5
Modified: Heap 5881 / CPU 7 - UOW with 100 Classes
Current: Heap 14331 / CPU 5
Modified: Heap 9937 / CPU 7 - UOW with 200 Classes
Current: Heap 22131 / CPU 6
Modified: Heap 13737 / CPU 6
Results Summary: The modified approach suggestion makes a fairly significant improvement on Heap usage but (to your concern) negatively impacted CPU slightly. The CPU numbers themselves are rather odd as the numbers are actually higher with smaller classes amounts in one case. To really be able to measure, a true load harness is needed to drive multiple tests, profile different areas at the method level and take averages. Curious if doing this type of performance testing is even possible on SFDC platform?
Conclusion: After writing the modified UOW to follow the new approach, current UOW approach is a little "cleaner" from a coding perspective therefore easier to support/maintain. Given that CPU difference is relatively unchanged (+/-) and even with the improvement in heap usage, I think the best course of action here is to not change the UOW as originally proposed in the OP. Instead, make it a best practice when dealing with "lots of classes" to construct the UOW with a specific class list rather than default to Application.UnitOfWork.newInstance. This could lead to inconsistent usage patterns in the code when "consuming" a UOW, but it's a fairly easy guideline and it keeps the UOW internals easier to support maintain and minimizes requirements on Heap/CPU.
Thoughts?
from fflib-apex-common.
Thanks for this John, great analysis and response! 👍
Yes i agree with your conclusion given your findings.
Though if code breaks away from Application.UnitOfWork.newInstance they also prevent mocking of the UOW via Application.UnitOfWork.setMock. So how about a Application.UnitOfWork.newInstance override that takes the list of SObjectType's?
from fflib-apex-common.
Thanks Andrew, I like the newInstance approach. In reviewing the code, this gets a little dicey and has some margin for error given the newInstance methods are not static and the mock could end having different types than those provided in the newInstance method call. For example, a mock could be set that contains a UOW with 5 SObjects while the newInstance method could be called that has 3 SObjects in the list. If setMock was called, the UOW would have 5 SObjects instead of the expected 3. This can be protected against by the person writing the test taking this in to account or some refactoring of the way this all works can be done. If the SObjectTypes were exposed as a read-only property off the UOW (it's currently a private), some checking could also be done in the newInstance overload.
I've created a pull request that takes the simplest approach. Let me know your thoughts.
Thanks!
from fflib-apex-common.
Thanks, i've merged the PR. 👍
from fflib-apex-common.
Related Issues (20)
- Unit test failure in multi-currency org HOT 4
- Deploy button doesn't deploy because there are test failures HOT 1
- Expected a QueryException due to read only user not having access to Opportunity HOT 7
- Switch to Inherited Sharing on SObjectDescribe and SObjectSelector HOT 2
- With latest fflib, do TriggerHandlers become service class consumers? If so what happens to UoW? HOT 6
- Selected tests in fflib_SObjectSelectorTest fail in an org with encryption enabled on Account.Name HOT 2
- Selector Mocks to Include SOQL Query Retrieve Check HOT 1
- fflib_SObjectUnitOfWork doCommitWork executes all dml for all registered types even if there are no changes
- Update README as session recordings are not available HOT 2
- fflib_SObjectDescribe.cls fails to resolve cross-object field paths for Person Accounts
- Aggregate SOQL support. HOT 2
- Disable Savepoint in tests HOT 4
- Inconsistent Code Coverage and Test Failures in fflib-apex-common HOT 1
- fflib_SObjectSelector and fflib_SObjectUnitOfWork have insufficient test code coverage. HOT 2
- Add queryWithBinds to Selector layer HOT 2
- Unit test failing fflib_SecurityUtilsTest & sysadmin_objectAndField_access HOT 8
- Coverage of UnitOfWork class HOT 1
- Versioning HOT 1
- fflib_SObjectSelectorTest failure with Lookup relationship and Person Type Accounts HOT 5
- fflib_SObjectSelectorTest Error: 'Assertion Failed: Expected: 12345.67, Actual: 9117.25' HOT 13
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fflib-apex-common.