Thursday, 7 November 2019

Dreamforce - It's a Marathon, Not a Sprint

Dreamforce - It’s a Marathon, Not a Sprint

At the time of writing (Nov 7th 2019) Dreamforce is 12 days away. This year will be my 10th consecutive year attending, which doesn’t seem possible but here we are. In spite of my best efforts, I have learned a few things over the years which may be of use to those heading for their first event.

Packing List

Comfortable Shoes

While this feelst like a hackneyed trope, it really is one of the best pieces of advice, especially if you are exhibiting. You’ll be on your feet a huge amount of time, especially once you factor in breakfast sessions and parties, so make sure you aren’t in agony from a couple of hours in. If you need to put on smart shoes (to present, for example), pack them in your rucksack and switch into them only for as long as you need them.

Battery Charger

While you might think your phone has plenty of charge, Dreamforce days are long days. Yes there are charging points, but do you really want to stand there for 45 minutes just charging your phone. It’s also a great way to make new friends if you have some charge to spare!

Space in your Case

You will pick up swag, water bottles and your Dreamforce backpack. Make sure you have enough room to get them home. Also, remember that when picking up your Dreamforce backpack, you may now have two backpacks to manhandle. This is surprisingly easy to forget and it gets real old real quick fighting your luggage all the time.

Exhibiting is Tough

The first year I went to Dreamforce was, like so much of my career, just dumb luck. BrightGen had decided to take a stand, and one of the sales team who was due work the stand took up an offer elsewhere. So a couple of weeks out I was suddenly going to Dreamforce, but on a Booth Staff ticket. This ticket allows you entry to the expo and keynote broadcast rooms and that’s about it, so any ideas I had about attending sessions were not to be. Not that I would have had any spare time anyway, as for some reason everyone was really interested in talking to us about service management contracts even though we were the other side of the world with an 8 hour time difference.

Working a stand is a hard job at Dreamforce, as it’s a multi-day event. Early starts and late finishes are the norm and you have to make sure you are ready to pitch your wares at a moments notice. Don’t underestimate the cumulative effect of four long days on your feet, typically followed by Salesforce or customer events, so you’re still on duty. This is one trip I really wouldn’t want to recreate.

Fitting in Sessions is Tough

One piece of advice I always give to those attending for the first time - don’t sign up for too many sessions, as you won’t get to them. However many you think you’ll be able to make, it will be less, for a variety of reasons including the following.

Moving Buildings Takes Time

Even if it seems like they are really close to each other, such as moving from Moscone West to the Hilton, which as the crow flies is about 50 yards. However, you have to get out of your breakout room, which will take a couple of minutes, longer if you have questions for the presenter. Then you’ll have to get down one or two escalators - if multiple sessions or a keynote have kicked out at this time, you’ll be queuing there for a while. Getting out onto the street from ground level is a snip, but then you have to cross the road. If it’s anything other than early in the morning you’ll find a few thousand people with the same idea, so you’ll have to wait a while.Then you’ll funnel in to the Hilton, figure out where the room is and if you are early enough, join the queue of registered attendees. If you haven’t allowed enough time you’ll find that general admission has been opened up and there are no seats left. Suddenly your planned-to-the-second agenda is blown to pieces and it’s just after lunch on the first day.

If the buildings are a long way apart (Rincon Center to Moscone, for example) it has taken me 30 minutes to get between them around lunchtime. Don’t forget that you are in the middle of a big city, so you have all the standard delays that come with that plus Dreamforce traffic on top.

You Will See People You Know

Even if everything else goes to plan, you’ll bump into someone you know, either in person or online, and stop to chat with them. When you finish chatting you’ll realise it is now 10 minutes into your next session, which is in a different building to the one you’ve been chatting in. This happens to me all the time.

Keynotes Are Busy

Marc Benioff’s keynote is crazy busy, and if you are planning to attend that in person then you really don’t want have anything else to do for at least an hour before. The queues will be huge, and the metal detectors won’t help.

Anything involving American politics will be popular - Hillary Clinton and Michelle Obama both generated queues around the block, which made any kind of movement, towards or away from the keynote, very difficult. I expect Barack Obama to be like this but multiplied several times.

Getting out of the main keynote rooms takes ages, as there are usually 5,000-15,000 people trying to funnel through 4 doors onto a few escalators. If you want to get anywhere quickly, either leave a few minutes early or wait 10-15 minutes.

The Trailhead Zone is Awesome

Once you get in there you won’t want to leave. But you’ll need to, in order to go to the next session that you’ve tried to cram in. So leave yourself some time to explore. I spend a lot of my time here.

Get to the Trailhead Zone Early

Most of the hands-on areas fill up really quickly, so if you don’t want to spend more time queueing, get there as soon as it opens. It also means that there will be plenty of swag once you’ve completed your challenge/trail/quest/whatever it is called this year. The lines for things like spinning the admin wheel of fortune, headshots, t-shirts etc are usually short or empty, so if you move quickly you can cover a lot of attractions in a short time.

And Stay There

As I mentioned earlier, I spend a lot of my time here. Not particularly for the hands on side of things, but for the theatre sessions. I usually prefer these to the full on breakout sessions as they are more bite sized and I can get a quick introduction to something I haven’t worked on before and if it piques my interest, I’ll then go off somewhere and learn more about it. There’s always a talk going on somewhere and you can just pitch up and start listening if something takes your fancy.

Don’t Forget your Badge and Lanyard

10 years ago you could get around with just the badge in your wallet, especially for the after parties. That’s no longer the case and you typically need the whole thing everywhere. Remember that you don’t have to wear it all the time on the street to advertise the fact that you are a tourist. 

You aren’t out with your Friends

By this I don’t mean that people are unfriendly or unhelpful, quite the reverse given the well-publicised Ohana community spirit. What I mean is that you aren’t out on the lash with a bunch of mates who will think it hilarious if you get smashed and cause a scene. You’ll be among colleagues, customers and partners who will expect you to behave in a professional manner. It’s very easy to undo a huge amount of work and hard-won goodwill with a single drunken episode, so always remember you need to stay in control.  Even if you don’t care about the effects on your own reputation and career, nobody else is there to watch you make an idiot of yourself.

It’s a Marathon not a Sprint

Dreamforce is four days, so don’t kill yourself trying to do everything on day one. This goes double for the parties - you won’t get much return on the investment for your trip if you are hungover all the time, and this will definitely reduce the sessions you can make it to (or stick around in!). If the lines are long in the Trailhead zone, get an early night and turn up first thing the the next morning - you’ll be glad you did.

Don’t feel bad about taking a time out whenever you need to. While there are mindfulness/quiet zones at the event, getting away from it all for a little while can be a nice change of pace. I usually walk down to the Embarcadero area and spend a few minutes looking at the bridges, boats and water.

Above all, have fun - don’t get so hung up on trying to do everything that you don’t enjoy the experience.

Don’t Miss Sessions

  • Mine
    I’m on at the Developer Theatre at 3:45 on Wednesday 19th, taking about UI Testing with Selenium and NodeJS.

  • Marc Benioff’s Keynote
    All the big announcements come at this keynote - there are plenty of overflow rooms if you can’t get there in person, and it will be streamed live.

  • Developer Keynote
    If you are a developer you’ll definitely want to see this one. Arrive early for decent seats.

  • Trailhead Keynote
    Always a riot and one of the loudest keynotes you’ll come across. Sit down the front to be deafened by excited MVPs! 

 

 

Wednesday, 30 October 2019

Auto-completing a Signature Capture Flow

Auto-completing a Signature Capture Flow

Introduction

One of the requests I’ve received from a couple of people around embedding Signature Capture is around automatically navigating once the signature has been captured. One request from the POV of users forgetting to click the Next/Finish button after saving the signature image, and one from the POV of not letting the user navigate further until they have captured a signature image. Luckily both of these can be handled via the same mechanism.

Taking Over the Flow Footer

Aura components that implement the lightning:availableForFlowScreens interface can manage navigation for the screen element they are embedded in. However, you do have to configure the screen so that the footer is hidden:

Once this is done, you have to control navigation via your aura component or the user will be stuck on that flow screen component for eternity.

Handling the Navigation

A lightning component that implements the lightning:availableForFlowScreens interface automatically receives the v.availableActions attribute, which lists the available navigation actions (prev/next etc). This is a collection of strings documented here. Executing a navigation action is as simple as accessing another implicit attribute, v.navigateFlow, and executing this with the desired action:

let navigate=component.get("v.navigateFlow");
navigate(‘FINISH');

Signature Capture With Navigation

In order to carry out the flow-specific navigation I’ve created a new component (SigCapFlowWithFinish). The component wraps an embedded SignatureCapture component and replicates its attributes so that these can be exposed in the flow builder. It also provides a handler for the SignatureCapturedEvt, fired when the user saves the signature image:

<aura:handler event="BGSIGCAP:SignatureCapturedEvt" action="{!c.handleCaptured}"/>

The handler for this event iterates the available actions and if it finds a next or previous, executes that. (Note that you can’t have both next and previous, so there’s no need to worry about ordering).

let flowAction=null;
let availableActions=component.get('v.availableActions');
for (let idx=0; idx<availableActions.length && null==flowAction; idx++) {
    let availAction=availableActions[idx];
    if ('NEXT'==availAction) {
        flowAction=availAction;
    }
    else if ('FINISH'==availAction) {
        flowAction=availAction
    }
}

if (null!=flowAction) {
    let navigate=component.get("v.navigateFlow");
    navigate(flowAction);
}

So when the user saves the signature, the flow auto-finishes or moves to the next element, and until they save the signature they can’t move forward. Here’s a quick video showing this for a flow launched from a contact record:

 

Share the Code, Share the Love 

You can find the component and it’s associated flow in the Signature Capture Samples repository, and here are direct links to the flow and component.

Related Posts

Saturday, 7 September 2019

Mentz - The Story Continues

Mentz - The Story Continues

Introduction

It’s been over three months since I launched Mentz on an unsuspecting Salesforce ecosystem, and the results have far exceeded my expectations. I’d have been quite happy with a couple of people attempting the challenges that I mentored myself, but it’s fair to say we are well past that. At the time of writing (September 2019) we have 90 mentees, 24 mentors and 45 solutions that have been mentored. The standard of mentoring is incredible - a lot of very smart people are putting a lot of effort into helping others in their development journey.

Release, Review, Repeat

  • Creating and maintaining the tooling around Mentz has been an interesting aspect for me, not least because of how wrong I’ve been about some of it. 
  • My original plan was to have two stages in a solution lifecycle - mentoring and publication. A mentee would iterate on their solution based on mentor feedback and when they were completely happy with it, publish it for the wider mentee community to see and comment on. This was pretty much entirely unsuccessful and just caused confusion about where to post solutions. We now have a single place where solutions are published which anyone can access.
  • Solutions were originally uploaded as chatter files until one of the Mentors asked me to turn on "Allow Inclusion of Code Snippets from UI” - now if the solution fits int the 10k chatter message limit it is uploaded as a snippet, which is a lot easier to respond to (thanks Adam Lasek).
  • The challenges typically involved a class with multiple methods to be built out. While I always created my own (unpublished) reference solutions, as I’d come up with the scenario it didn’t take me very long. When a few solutions stacked up and I mentored them on a weekend, it took me almost all day! So I created a couple of short challenges to see what kind of reception they would get.
  • I used to regularly post into the Mentor group to let everyone know if there were any solutions awaiting a response. This always lead to apologetic replies from the Mentors, which wasn’t what I was after at all - I just wanted to avoid them having to poll the org to see if there was anything they could help with. I replaced this with a lightning web component rendered in in the Mentors group home page that listed any unanswered solutions, which seems to have helped.

There have also been some other changes to try to make things easier/more interesting:

  • A Suggestion Box repository for mentees (or anyone really) to suggest challenges they’d like to take
  • The ability to lock a solution to a single mentor. The idea here is that a mentor claims a solution and is the only one (aside from the original author) that can respond to it. I haven’t turned this on yet as AFAIK we’ve only had one instance where two mentors were working on responses to the same solution at the same time.
  • Mentee and Mentor leaderboards - people seem to like these so I’ve added them to the group home pages. I’m at the top of the Mentor leaderboard, but only because I mop up any solutions that haven’t had a response after a few days. I don’t have to do this, but I do feel a sense of responsibility having enticed mentees to join.
  • The Mentz Salesforce CLI plugin now has a challenges topic that lists the available challenges (optionally including those already completed) and clones the repo for the user:
            $ sfdx mentz:publish --targetusername myOrg@example.com --all

              Select a challenge
              1) COLLECTION SIMPLE 1
              2) CONDITIONAL SIMPLE 1 (Completed)
              0) Quit

              Choose a challenge: 1
              Cloning repository = https://github.com/mentzbb/SimpleCollections1
              ...
             Done

What’s Next

As I wrote in my original Mentz blog post:

If things do take off, I don’t want to handle everything out of a single org myself, as that will limit scale. Instead I'll make the code available as a package so that others can host their own instance of Mentz, in their own org. We'll all use a common set of challenges, but the actual mentoring will be distributed.

With 90 mentees it feels like my first org is getting pretty close to as big as I want it to get, so it’s time to test the waters and see if anyone else wants to host Mentz. Here’s a few things to think about before you jump in:

  • This will be a developer edition setup by me that you then take over - this isn’t (only) because I’m a megalomaniac, but more because I want to go through the setup a few times to get it documented before leaving people to face it on their own. The Mentz code will be deployed as unpackaged code  - it might be packaged up in the future, but at present it won’t add much and just adds more work for me :) It does also allow me to keep an eye on the standard of mentoring, as it’s been stellar so far and I’d like to keep it up there.
  • There’s not very much housekeeping - mostly it’s emailing the Mentee/Mentor requestors and then executing a lightning action to convert the request to a user. I usually do half a dozen or so a week.
  • The challenges are the same for every Mentee, all that changes is the org they post solutions to and who mentors.
  • If you host a Mentz instance, be prepared to act as the Mentor of last resort - this doesn’t happen often, but I think it’s quite important to make sure that posts are getting answered. I usually allow about a week for the mentors to dive in and then start picking things up myself, usually over the weekend.
  • Lots of people will register an interest and never even login - remember that this is Mentz where we do what we want, so this is absolutely fine. Never try to make people do anything, although it’s okay to check from time to time to make sure they aren’t trying and struggling/failing.
  • You need to have some reach to attract Mentees/Mentors - I’d imagine it’s a bit dispiriting to announce this is happening and receive zero interest :)

If this sounds like the sort of thing you’d be interested in, fill in the short form at https://bobbuzz.me.uk/MentzHosting - it will almost certainly take me a week or two to do anything so don’t panic if you don’t hear back quickly.

Related Posts

 

 

Sunday, 1 September 2019

Parallel Apex Unit Tests and Salesforce CLI Plugins

Parallel Apex Unit Tests and Salesforce CLI Plugins

 

Introduction

In the Salesforce Winter 20 release notes was something I’ve been looking forward to for a few years - the ability to turn off parallel Apex unit test execution. By default parallel unit test are enabled (somewhat confusingly, by the fact that the Disable Parallel Apex Testing option is not checked):

 

and this typically results in a number of failures in my automated test runner package, as the tests can’t get exclusive access to write to the account others object tables.

This setting is one of the last items that I have to manually turn on when creating a scratch org, and that has been annoying me for a while. I could automate it via Selenium, but that feels like overkill, so I was very pleased to see the new Apex Settings metadata type. Among other features, this has the enableDisableParallelApexTesting field which allows me to check or uncheck the Disable Parallel Apex Testing checkbox, albeit via a metadata API deployment. The release notes also mentioned the to-be-deprecated OrgPreferenceSettings metadata object, and it turns out that this also has a mechanism for turning off parallel testing via the DisableParallelApexTesting setting, so there was no need for me to wait until Winter 20 as long as I could switch between the two mechanisms based on the API version the org is at.

Salesforce CLI Plugin

Regular readers of this blog will know that I’m a huge fan of the Salesforce Cli - I use it all the time and when I’m looking to do anything around developer tooling I always try to create a CLI plugin to host it. This was no different, although it presented a couple of challenges that I hadn’t taken on before:

  • Determining the API version that the org is at. If this is 46 or less (not sure how it would be possible to be on an earlier version of the API than Summer 19, but if Salesforce ever allow it I wanted to be covered) I need to deploy an OrgPreferences metadata type, 47 or higher I need to deploy an ApexSettings.
  • Metadata deployment from inside a plugin. 

After I scaffolded a new bbsfdx plugin and copied the commands/hello/org.ts example command to bb/test/parallel.ts, I set about solving them.

Determine the API Version

Whenever I’m doing anything new with a CLI plugin, my first port of call is the reference documentation for the Salesforce DX Core Library, and I wasn’t disappointed. I can find the API version for the org via the Connection.retrieveMaxAPIVersion function. Getting a Connection object is simple in a CLI plugin - just specify the requiresUsername property as true and a connection comes up with the rations via the org property supplied by the plugin. Getting the target API version is as simple as:

const conn = this.org.getConnection();
const apiVersion = await conn.retrieveMaxApiVersion();

So far so good.

Metadata Deployment

The simplest way to do this is to execute an existing Salesforce CLI deployment command, either force:source:deploy or force:mdapi:deploy, but I’m not a fan of this approach. Spawning a process to execute a Salesforce CLI command from within a CLI plugin seems clunky and inelegant, and it binds me to a command that I don’t control and which may be retired. I should be able replicate anything the standard commands do as I have access to the same underlying libraries.

This time the core library docs weren’t much help - there was a metadata property on the Connection object, but it didn’t have any detail, so time to look elsewhere. The Core library is built on Shinichi Tomita’s JSforce library, so I headed over to the docs for that. The API reference for the Metadata class was exactly what I was looking for, specifically the deploy method.

To deploy metadata, I need a zip file containing a manifest (package.xml) and the metadata files themselves in the directory structure mandated by the metadata API. In order to achieve this, I create a temporary directory and write the appropriate information depending on the API version (stored as a float value in the fltVersion variable):

let packageFile=join(targetDir, 'package.xml');
let packageContents='<?xml version="1.0" encoding="UTF-8"?>\n' + 
    '<Package xmlns="http://soap.sforce.com/2006/04/metadata">\n' +
    ' <types>\n' + 
    '   <name>Settings</name>\n';

let fltVersion=parseFloat(apiVersion);

if (fltVersion>46) {
  packageContents+='    <members>Apex</members>\n' + 
                   '  </types>\n' +
                   '  <version>47.0</version>\n' + 
                   '</Package>';
  let apex=join(settingsDir, 'Apex.settings');
  writeFileSync(apex, 
        '<?xml version="1.0" encoding="UTF-8"?>\n' + 
        '<ApexSettings xmlns="http://soap.sforce.com/2006/04/metadata">\n' +
        '  <enableDisableParallelApexTesting>' + attr + '</enableDisableParallelApexTesting>\n' +
        '</ApexSettings>\n'
          );
}
else {
  packageContents+='    <members>OrgPreference</members>\n' + 
                   '  </types>\n' +
                   '  <version>46.0</version>\n' + 
                   '</Package>';
  let orgPref=join(settingsDir, 'OrgPreference.settings');
  writeFileSync(orgPref, 
    '<?xml version="1.0" encoding="UTF-8"?>\n' + 
    '<OrgPreferenceSettings xmlns="http://soap.sforce.com/2006/04/metadata">\n' + 
    '  <preferences>\n' + 
    '     <settingName>DisableParallelApexTesting</settingName>\n' + 
    '     <settingValue>' + attr + '</settingValue>\n' + 
    '  </preferences>\n' + 
    '</OrgPreferenceSettings>\n'
  );
}

writeFileSync(packageFile, packageContents);

Now I have my directory structure, I need to zip it. Searching on npm for zip packages returns a lot of results, so how to choose? I bounced around sites like stack exchange to see what others were using and eventually settled on compressing for a couple of reasons. First, it supports other compression files than zip, and I might need that flexibility in the future, and second it has a really simple API and is already promisified. After installing it into my plugin node modules and importing it into the parallel.ts file, generating a zip file is a couple of lines:

const zipFile=join(tmpDir, 'pkg.zip');
await compressing.zip.compressDir(targetDir, zipFile);

Getting there. Back to the docs for the metadata deploy function, it wants a zip stream rather than a filename, so I create one of those and add the code to deploy the metadata;

let zipStream=createReadStream(zipFile);
let result=await conn.metadata.deploy(zipStream, {});

The deploy function returns information about the deployment job, so I then enter a loop to poll for the status until it is finished:

let done=false;

let deployResult:DeployResult;
while (!done) {
  deployResult=await conn.metadata.checkDeployStatus(result.id);
  done=deployResult.done;
  if (!done) {
    this.ux.log(deployResult.status + messages.getMessage('sleeping'));
    await new Promise(sleep => setTimeout(sleep, 5000));
  }
}

and there it is - a plugin to enable or disable parallel Apex unit testing in under a couple of hundred lines of Typescript (and obviously a ton of existing node modules that allow me to stand on the shoulders of giants). 

Where’s the Code?

The full code for the plugin can be found in the Github repository at : https://github.com/keirbowden/bbsfdx 

The plugin itself is published on npm at : https://www.npmjs.com/package/bbsfdx - it has been tested on MacOS.

To install the plugin into your version of sfdx, execute:

sfdx plugins:install bbsfdx

Related Posts

Monday, 26 August 2019

Salesforce Unlocked Packages and Supplementary Code

Salesforce Unlocked Packages and Supplementary Code

Introduction

Unlocked packages have been Generally Available since the Winter 19 release, so almost a year at the time of writing (August 2019). Unlike 1.0 packaging, source of truth is the version controlled source, rather than the contents of a packaging org. In fact the only time you need anything other than a scratch org is if you are namespacing your package, in which case you’ll have to create a developer edition to annex the namespace. In packaging 2.0 the contents are determined by the code on the filesystem where you run the packaging commands and the Salesforce DX project configuration file (sfdx-project.json).

I’m not going to go into the detail of creating and publishing packages - the Trailhead module does a pretty good job of introducing the concepts, and if you want a deep dive then check out Fabien Taillon’s blog post about how Texei moved to unlocked packages (they were called Developer Controlled Packages back then, but the principles apply even if the commands have changed slightly.

SalesforceDX Project File

To generate an unlocked package, you need to define where the code lives in your SalesforceDX project file. Here’s the key part of the file for an example package:

"packageDirectories": [
        {
            "path": "force-app",
            "default": true,
            "package": "bbexample",
            "versionName": "Version 1.0",
            "versionNumber": "1.0.0.NEXT"
        }
    ]

When I run the Salesforce CLI commands to generate a package version, everything under the

force-app

directory will be added to the package and uploaded. And this to my mind is a key difference between 1.0 and 2.0 packaging. In 1.0 I create the package from the packaging org and I get to choose which components get added. In 2.0 not so much - everything that I have under the packaging directory goes in.

Supplementary Code

When I create a package there is typically a bunch of supplementary code that helps the development and test process, but I don’t want going into the package. If the package contains Lightning Web Components for example, I might have a flexipage with a  number of instances of the component showing various aspects of the functionality, allowing me to see at a glance that everything is working correctly. If the package works against generic sobjects, I might have some sample sobjects to execute tests against that I don’t want ending up in the subscriber org. I want these items available in the scratch o rgs where I’m developiing the package, but I don’t want to release them. In 1.0 I could just avoid adding them to the package, but in 2.0 I need a way to separate them from the packaged code. I could keep it in a separate repo, but that adds complexity to the development setup, and it’s always best to keep things as simple as possible.

Multiple Package Directories

The SalesforceDX project file can define multiple package directories for a single project. When you execute force:source:push, the contents of all of these directories are pushed to the scratch org, so i can store my supplementary code in another subdirectory and have it included in the development process. 

"packageDirectories": [
        {
            "path": "force-app",
            "default": true,
            "package": "bbexample",
            "versionName": "Version 1.0",
            "versionNumber": "1.0.0.NEXT"
        },
        {
            "path": “supplementary",
            "default": false
        }
    ]

When I push to my scratch org, the contents of both the force-app and supplementary subdirectories will be deployed, but when I generate a package version, only the directory with the package attribute gets included. All of my supplementary code stays out of the package and by extension the subscriber org.

There is one wrinkle to this - if I make some changes in the scratch org, when I execute force:source:pull to retrieve them, they will go into the package directory with the default attribute set to true - in this case force-app. If I don’t want these items in the package, I have to manually move them over to the supplementary subdirectory. Not a huge amount of effort but easy to forget.

Bonus - Installations via the CLI

If you haven’t used packaging in conjunction with the CLI yet, there’s one killer feature. Anyone who has worked with packaging 1.0 knows the fun and games around uploading a package, receiving the email that it has been published, then trying and failing to install it as it turns out not to be available after all. There’s a perfectly sound explanation for this - the emails means it was successfully uploaded to wherever packages live, but after that it has to be propagated around Salesforce infrastructure world, and until it’s made it to the instance you are trying to install in, you’ll get failures.

When you install via the CLI force:package:install subcommand, you can specify two wait times. The --wait switch that, like many other commands, specifies how long to wait for the command (installation) to complete, and the —publishwait that specifies how long to wait for the package to become available to the subscriber org. I typically specify big numbers for both of these switches and then fire and forget the installation. It’s a far less stressful user experience!

Related Posts

 

Saturday, 3 August 2019

Mentz - Where We Do What We Want!

Mentz - Where We Do What We Want!

Introduction

In the TV adaptation of David Peace’sRed Riding" quartert of books, there’s a great scene where a group of corrupt West Yorkshire policemen are toasting their success in moving towards controlled vice : "Off the streets and out the shop windows, under our wing and in our pocket”. The final line of the toast is “To the North - where we do what we want!”.

An unusual introduction to a tech blog post, I’m sure you’ll agree, but there is a link, however tennis. Doing what we want is the ethos behind the Mentz community initiative (and I’ve always loved that scene).

Moar Developers

One reason I started Mentz is that we need more developers in the Salesforce ecosystem, and by developers I mean people that can write code to solve complex business problems, understanding the fine details of the Apex language and the pros and cons to specific approaches. There are plenty of initiatives around to get started learning Apex, but not too many where a more experienced developer casts an eye over your code and gives you feedback, about things both good and bad, and pointing you to resources where you can learn more.

Tapping into Top Talent

Another reason I started Mentz is that I felt we were missing out on accessing a lot of top talent by insisting on commitments to a set number of weeks, or a fixed set of hours (duration and/or fixed start/end times). People at the very top of our profession often can’t make those type of commitments - they don’t have that many hours to spare, they can’t commit to specific hours every week, or they are subject to the whims of a project or customer which means that plans have to change at the last minute. These people are often running companies so they can’t step away when the pressure is on. The upshot of all this is that they may not be participating as much as they want to, because they don’t want to let others down. This is a crying shame, as these are often extremely experienced and talented developer who have a lot to share.

Fear of Commitment

When you join Mentz, as a mentor or mentee, you commit to absolutely nothing. Nada. Zip. When you register an interest, you’ll receive a chatter login and if you never sign in, that’s fine. Mentors don’t get assigned mentees, and vice versa. Mentors and mentees aren’t assigned to each other, it’s much more relaxed than that. If a mentee feels like taking a challenge, they do so and upload their solution to the challenge chatter group. If a mentor feels like looking at someone’s work and giving feedback, they pick any unanswered solution (there’s a lightning web component that shows these, because we don’t want mentors wasting their valuable time scouring chatter groups). There are no programs, timelines, schedules, courses. Just people who take challenges and people who review the solutions, doing what they want when they want to. I’m not the boss of you, and nor is anyone else.

Dipping a Toe

If you’ve been put off signing up for Mentz because you think you might disappoint your assigned mentor or mentees, don’t be. If you want to try the challenges without signing up you can, just take a look at the Github organisation - you won’t be able to submit your solution until you sign up for Mentz, but it will give you an idea of what is involved. If you want to sign up for Mentz, head over to the home page and follow the appropriate signup link. It might take a while for your request to be approved, as I also do what I want with regard to Mentz, but it will happen eventually.

And Finally

Please join me in raising a glass to Mentz - where we do what we want!

 

Related Posts

 

Sunday, 23 June 2019

Mentz - The Mentee Workflow

Mentz - The Mentee Workflow

This post was updated on 03/08/2019 to remove the concept of separate mentoring and solutions chatter groups for a single challenge - this turned out to be confusing so we now have a single chatter group per challenge.

 

Introduction

Mentz has been around for a couple of weeks now and we’ve had our first solutions published from Jesse Twum-Boafo that received some great mentoring from Clara Perez. The one key thing that this tells me is that the process works - up until now it was only me that had been through this so I had no idea if it would work on anyone else’s setup. Now that I know it does I’ll start adding the rest of those people that have registered an interest in being a Mentor or Mentee, so if you have registered, look out for an email. 

I’m also getting rid of the ask that anybody registering be in the same timezone. I originally added this because I had some weird idea that people could only register for a single Mentz login, but I’ve since realised that this is bonkers - there’s no reason why someone can’t cut their teeth in my instance and then start/join another instance to leverage that experience. There’s also no reason why someone couldn’t have a login to every Mentz instance there is, although I’d be rather suprised if that was the case as Mentz is aimed at those that don’t necessarily have a huge amount of time. I guess we’ll see what happens.

Mentees

One area I don’t think I’ve done a fantastic job on so far is explaining the Mentee process, so a blog post dedicated to this seemed an appropriate next step.

Mentz Login

The first thing a Mentee needs is a login to a Mentz instance. Without one of these you are still free to work on the challenges, but you won’t be able to publish your solutions and receive mentoring. To sign up for a login, visit the Candidate Signup page. (I’ve also not been very consistent about what to call Mentees, but I hope to improve upon that!).

Git and Github

The Mentz challenges are hosted on Github and you need to use Git to create your local copy. If you haven’t used Git before, complete the Git and Github Basics Trailhead module.

Salesforce CLI Plugin

The next thing a Mentee needs to do is install the Mentz Salesforce CLI Plugin. This provides the solution publishing capability, ensuring that the solution is published to the correct chatter group in the appropriate format. 

If you don’t have the Salesforce CLI installed, head over to the Home Page and follow the instructions.

Once the CLI is in place, install the Mentz plugin by executing the following command:

sfdx plugins:install mentz

You can verify that the installation was successful by executing:

sfdx mentz -h

and confirming that you see the following output:

Mentz commands

USAGE
  $ sfdx mentz:COMMAND

COMMANDS
  mentz:publish publishes a solution, optionally asking for mentor feedback

Finally, authorise the Salesforce CLI to use your Mentz login:

sfdx force:auth:web:login -a MENTZ

when the browser opens, login using your Mentz instance credentials. The ‘-a MENTZ’ switch creates a shortcut alias of ‘MENTZ’ which you can use when submitting challenges - use anything you like here, but remember to replace any instances of ‘MENTZ’ in the examples below with your chosen alias.

And that’s it - you are now all set to take on a challenge.

Challenges

All Mentz challenges live at the mentzbb organisation on Github - each challenge has a brief description of what it covers:

Click into a challenge to see the underlying details and code. If you want to take a challenge you need to clone the repository and change some of the code. For the purposes of this post I’ll be using the SimpleConditional challenge as an example, but all challenges follow the same pattern.

First step is to clone the repository - there’s a helpful button on the challenge main page to steer you in the right direction

Click the ‘Clone or Download’ dropdown button and you can copy the URL you need to clone. 

I use Git from the command line, so from my home directory I execute:

$ git clone https://github.com/mentzbb/SimpleConditional1.git

which does its thing and produces the following output:

Cloning into 'SimpleConditional1'...
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 25 (delta 7), reused 19 (delta 4), pack-reused 0
Unpacking objects: 100% (25/25), done.

The contents of the repository are as follows:

Where:

  • CHALLENGE is a file that the Salesforce CLI plugin uses to determine which challenge this is.
  • force-app contains the source format version of the challenge.
  • README.md is the home page for the challenge repository on Github.
  • src contains the metadata format of the challenge.

Completing a Challenge

To complete a challenge, you build out the sample class so that all the tests in the associated test class pass.

In the case of the SimpleConditional1 challenge, the sample class to be built out is SimpleConditional1.cls, and the tests from SimpleConditional1_Test.cls need to pass to complete the challenge. It doesn’t matter which of the source or metadata format classes you build out, and you only need to build out one of them.

Each method in the sample class has a comment that explains what processing it needs to carry out, e.g.

public static Boolean IsPositive(Integer num)
{
    // change this method to return true when
    // the number is greater than zero and false otherwise
    return null;
}

In order to run the unit tests, you need to send the code to a Salesforce instance. There are several ways of doing this, detailed in the following sections.

Scratch Org Development

If you want to develop against a scratch org, you’ll work on the source format code. Edit the code under the force-app directory and send to the scratch org using the command:

sfdx force:source:push

You can execute the tests in the org using the developer console, or the Salesforce CLI command:

sfdx force:apex:test:run -t SimpleConditional1_Test

Once you are happy with your code, you can request mentoring using the command:

sfdx mentz:publish -c "<comment>" -u MENTZ -m
-f ./force-app/main/default/classes/SimpleConditional1.cls

Where ‘<comment>’ is anything you wish to say to draw the mentor’s attention too.

Developer Edition Development

If you want to work against a developer edition, you’ll work on the metadata format code. You will need to authenticate the Salesforce CLI against the developer edition instance using the same approach as you did to authenticate against Mentz - don’t forget to set up a different alias!

Edit the code under the src directory and deploy to the developer edition using the command:

sfdx force:mdapi:deploy -d src -w 10 -u <username>

Where <username> is the alias for this org.

You can execute the tests in the org using the developer console, or the Salesforce CLI command:

sfdx force:apex:test:run -t SimpleConditional1_Test -u <username>

If you don’t want to actually deploy the code anywhere, but just run the tests, you can add the -c switch and ask the deploy command to run the tests using the following command:

sfdx force:mdapi:deploy -d src -w 10 -u <username> -c
-t SimpleConditional1_Test

Once you are happy with your code, you can request mentoring using the command:

sfdx mentz:publish -c "<comment>" -u MENTZ -m
-f ./src/classes/SimpleConditional1.cls

Where ‘<comment>’ is anything you wish to say to draw the mentor’s attention too.

Using the Developer Console

If you don’t want to deploy the code, you can use the developer console as follows:

  1. Open the developer console
  2. Click the File menu and select New -> Apex Class
  3. Name the Apex class SimpleConditional1
  4. Copy the contents of the force-app/main/default/classes/SimpleConditional1.cls and paste this into the new apex class.
  5. Save the class
  6. Click the File menu and select New -> Apex Class
  7. Name the Apex class SimpleConditional1_Test
  8. Copy the contents of the force-app/main/default/classes/SimpleConditional1_Test.cls and paste this into the new apex class.
  9. Save the class
  10. Work on the SimpleConditional1 apex class as you usually would until all the tests in SimpleConditional1_Test pass.
  11. Copy the contents of the SimpleConditional1 class from the developer console and paste this into force-app/main/default/classes/SimpleConditional1.cls in your local filesystem.

You can then publish a solution, optionally requesting mentoring using the command:

sfdx mentz:publish -c "<comment>" -u MENTZ -m
-f ./force-app/main/default/classes/SimpleConditional1.cls

Where ‘<comment>’ is anything you wish to draw the mentor’s attention to and the ‘-m’ switch adds a comment requesting mentoring.

Discussion

Once you have published your solution, a Mentor will pick this up when one is available. As the idea behind Mentz is that people dip in when they have time, it may take a few days before anyone responds. It will be worth the wait.  The discussion takes place in a chatter group dedicated to the specific challenge, so you just login with your Mentz credentials and start talking.

Still in Beta

Mentz is still in beta, so things are likely to change, for example:

  • Now that Summer 19 is live and deployment from source format to non-scratch orgs is GA, the metadata format version of the challenges will be going away
  • Separate commands and chatter groups for mentoring and publishing solutions may be merged.

Related Posts

 Follow @bob_buzzard