All Blog Posts - page 2
Nov 17, 2022 - Unity Unit Testing Beyond the Basics
Filed under: #tech #unity #gamedevOne of the things that’s great about Unity is that you can find pretty much whatever information you need online. Docs aren’t too bad, but the community has done forum posts, blogs, YouTubes and all sorts of content over the years. One thing I just haven’t been able to find though, is any information on using unit testing beyond just the basics of getting set up. So, basically, all that was left is trial & error. Here’s the questions I answered for myself.
Feb 12, 2022 - 20 Years of Dynamics
Filed under: #daxmusings #bizappsAlmost 20 years ago, in July of 2002, Microsoft acquired Dynamics AX. Several months later, in October 2002, I landed my first job and started learning X++. AX3.0 had just dropped, but the company I worked for in Belgium still had some AX2.5 implementations going on. Unforgettable implementations were the one that was using Oracle as its database, another was implementing AX2.5 “enterprise portal” which at the time was an ASP site calling X++ classes over a COM connector, with X++ classes returning strings of HTML.
Nov 22, 2021 - Changes To Internal Access modifier in X++
Filed under: #daxmusings #bizappsIn the upcoming April 2022 release (version 10.0.25/PU49), some changes will be introduced to how the internal access modifier works in X++. Although still not as strict as C#, it will at least fix a few issues with how it works. Note that the InternalUseOnly
attribute is a different feature altogether, and still only generates warnings.
Before we dive into the changes, let’s understand why and when internal is used. Essentially, marking something as internal allows only the code in the same assembly to access it. In X++, an assembly is a package so only models in that package can access the internal code. The reason to use this isn’t much different from using private methods or members, except the allowed scope to use the code is the whole assembly and not just the class. In the context of Finance and Operations apps and X++, marking code as internal allows engineers to build the code but give themselves the option of changing the signatures of their code without worrying of breaking any code that extends it.
Note that the InternalUseOnly
attribute is a different feature altogether, and still only generates warnings.
Summary
- If you make use of the
internal
access modifier in your own code (declare methods or classes internal) you likely want to review the details below and you may have to fix some issues in your code. Since you’re in full control of your own code, this should not present any problems. - For all other code, the only potential issue happens when your code is using INHERITANCE on a Microsoft class and the code is trying to override an internal method and/or changing its access modifier.
- All code with
InternalUseOnly
attributes is still only giving warnings.
Details
I’d like to thank the team and specifically Laurent for not only working on these compiler issues, but providing the following detailed examples of the changes.
The issues with internal that were corrected, are largely around how inheritance works and what the compiler allows or does not allow you to do. Let’s go right into the details. I encourage you to also read Peter Villadsen’s blog post on the matter.
A public class shouldn’t be allowed to extend an internal class
internal class ClassA {}
public class ClassB extends classA {} // classB is in the same model as classA
This scenario was changed from a warning to an error (the message remaining the same: InconsistentAccessibilityInheritance: Base class 'ClassA' is less accessible than class 'ClassB'
).
Since customer code cannot extend our internal classes to begin with, this will not impact customer code that extends Microsoft code. Customer code will be impacted if it declares its own internal class and publicly derives from it.
An internal class couldn’t be used as an internal member + misleading message
internal class ClassA {}
public class ClassB // ClassB is in the same model as ClassA
{
internal ClassA a;
public ClassA b;
protected ClassA c;
private ClassA d;
}
This scenario used to result in the following errors:
Error: InconsistentFieldAccessibility: The type 'ClassA' of the member variable 'a' is internal to Model 'MyModel' and is not accessible from model 'MyModel'.
Error: InconsistentFieldAccessibility: The type 'ClassA' of the member variable 'b' is internal to Model 'MyModel' and is not accessible from model 'MyModel'.
Error: InconsistentFieldAccessibility: The type 'ClassA' of the member variable 'c' is internal to Model 'MyModel' and is not accessible from model 'MyModel'.
With the change, this results in the following errors:
Error: InconsistentAccessibility: field type 'ClassA' is less accessible than field 'b.ClassB'
Error: InconsistentAccessibility: field type 'ClassA' is less accessible than field 'c.ClassB'
This is mostly LESS restrictive than before. Customers COULD be impacted if their code is exploiting the compiler issue where private use of non-accessible internal types was allowed.
Overriding an internal method in the same package and increasing visibility was not diagnosed as an error
class Base { internal void method() {} }
// in the same model as Base
class LocalA extends Base { public void method() {} }
class LocalB extends Base { internal void method() {} }
class LocalC extends Base { protected void method() {} }
class LocalD extends Base { private void method() {} }
This resulted in the following errors:
LocalC.xpp(3,5): OverrideMoreRestrictive: OverrideMoreRestrictive: Method 'LocalC.method' cannot have a more restrictive visibility than the method 'Base.method' which it overrides.
LocalD.xpp(3,5): OverrideMoreRestrictive: OverrideMoreRestrictive: Method 'LocalD.method' cannot have a more restrictive visibility than the method 'Base.method' which it overrides.
This will now result in the following errors:
LocalA.xpp(3,5): CannotChangeAccess: 'LocalA.method' cannot change access modifiers when overriding inherited method 'Base.method'
LocalC.xpp(3,5): CannotChangeAccess: 'LocalC.method' cannot change access modifiers when overriding inherited method 'Base.method'
LocalD.xpp(3,5): CannotChangeAccess: 'LocalD.method' cannot change access modifiers when overriding inherited method 'Base.method'
Customer code will only be impacted if in their own model they have an internal method and override it publicly.
class Base { internal void method() {} }
// in a different model than Base
class DerivedA extends Base { public void method() {} }
class DerivedB extends Base { internal void method() {} }
class DerivedC extends Base { protected void method() {} }
class DerivedD extends Base { private void method() {} }
This used to result in the following errors:
DerivedB.xpp(3,5): InvalidOverrideIntenalMethod: Method 'method' in class 'Base' is internal and is not allowed to be overriden.
DerivedC.xpp(3,5): OverrideMoreRestrictive: OverrideMoreRestrictive: Method 'DerivedC.method' cannot have a more restrictive visibility than the method 'Base.method' which it overrides.
DerivedD.xpp(3,5): OverrideMoreRestrictive: OverrideMoreRestrictive: Method 'DerivedD.method' cannot have a more restrictive visibility than the method 'Base.method' which it overrides.
It is now diagnosed as:
DerivedA.xpp(3,5): CannotChangeAccess: 'DerivedA.method' cannot change access modifiers when overriding inherited method 'Base.method'
DerivedB.xpp(3,5): InvalidOverrideIntenalMethod: Method 'method' in class 'Base' is internal and is not allowed to be overriden.
DerivedC.xpp(3,5): CannotChangeAccess: 'DerivedC.method' cannot change access modifiers when overriding inherited method 'Base.method'
DerivedD.xpp(3,5): CannotChangeAccess: 'DerivedD.method' cannot change access modifiers when overriding inherited method 'Base.method'
Customer code will only be impacted if it is exploiting the existing gap in the compiler where publicly overriding a non-accessible internal method wasn’t diagnosed.
Feb 27, 2021 - Use The New Packaging in the Legacy Build Pipeline
Filed under: #daxmusings #bizappsThe legacy pipeline from the build VM has its own PowerShell script that generates the packages. However, it always puts the F&O platform version into the package file name which can make it more difficult to use release pipelines or including ISV licenses into your packages since the version number changes with each update, requiring you to update your pipeline settings (and finding out the actual build number to use). Continue reading below or watch the YouTube video to learn how to swap the packaging step from the legacy pipeline with the Azure DevOps task which lets you specify your own name for the deployable package zip file. You can find the official documentation on the packaging step here.
Jan 27, 2021 - ISV Licenses in Packages
Filed under: #daxmusings #bizappsISV licenses for Dynamics 365 F&O can only be applied using deployable packages. There are ISV license packages that only contain a license, and there are combined packages that have both the binaries as well as the license. But now with all-in-one packages on self-service environments, you can only apply the license as part of an all-in-one package. So what are your options? Check out my YouTube video and/or read on for more details.
Jan 23, 2021 - Updating The Legacy Pipeline for Visual Studio 2017
Filed under: #daxmusings #bizappsWith the upcoming April 2021 release, support for Visual Studio 2015 will be dropped. If you’re building your code using a build VM deployed from LCS, you’re using the legacy pipeline. You will have to manually update your build pipeline tasks to use the new version. The steps are fairly simple and outlined in this official docs article. I have a quick video on YouTube to walk you through this as well. There is one little flag that could trip you up, however.
Jan 18, 2021 - Including ISV Binaries in Your Package
Filed under: #daxmusings #bizappsMany ISVs supply their Dynamics 365 Finance / Supply Chain solutions in a deployable package, which only contains binaries. With the current enforcement (“all-in-one package”) of a long-standing best practice to deploy all code together all the time, some customers are only now faced with figuring out how to “repackage” an ISV’s binaries into their own package. In this post I will outline a few gotchas in addition to the official documentation, for both the legacy build pipeline and the new build pipeline. You can also watch a quick overview video I made here on YouTube.
Dec 17, 2020 - The Making Of
Filed under: #techWelcome to my new site. I’ve been wanting to blog more, but include topics unrelated to Microsoft Dynamics. I wanted a place to put some of the game development stuff I do. And as I’m considering to get into some regular streaming, I want a landing place for anyone checking me out. So, here we are. I started daxmusings.codecrib.com in 2010 on blogspot aka blogger. I attached the custom domain to it at a later time, keeping the daxmusings subdomain. I’ve had stuff on www.codecrib.com on and off, never very interesting. I’ve hosted it in several different ways over the years, most recently as a GitHub Pages site with custom domain attached.
Oct 31, 2019 - Pushing, Dragging or Pulling an Industry Forward
Filed under: #daxmusings #bizappsQuite a few years ago, in my previous job when I was an MVP still, I did an online webinar for the AXUG called “Putting Software Engineering back in Dynamics AX” (in 2014). Admittedly it was somewhat of a rant / soap box type of talk. I guess “food for thought” would be a more optimistic characterization. I did try to inject some humor into the otherwise ranty slides by adding some graphics. At the time we were building out our X++ development team and we were heavily vested in TFS and automation, and I was very keen on sharing our lightbulb moments and those “why did we only start doing this now” revelations.
Fast forward 5 years to a new generation of technology and a shift to cloud. In fairness, many more people are engaged in some of these topics now because the product finally has features out of the box to do builds, use source control without tons of headaches and setup, etc. But contrary to the advice on one of the original slides from 2014 that said “Bring software engineering into AX, not the opposite” - it sort of feels that is exactly what has happened. People projecting their AX processes onto some software engineering processes. Sometimes ending up with procedures and technology for the sake of it, and not actually solving any problems at all and sometimes even creating more problems. But, they can say they ticked another checkbox on the list. I have stories of customers with messed up code in production, because someone setup branching because they were told that’s a good thing to have. Yet nobody knew what that meant or how to use it. So code was being checked into branches left and right, merged in whichever direction. Chaos. A perfect example of implementing something without having a good reason or understanding to do so. On the flipside, we have customers calling us up because they “redeployed” their dev VM, and want to know how they can get a clean copy of their code from production back into their VM. Now, part of that is legacy thinking and not understanding the technology change. But honestly that was never a good thing in older versions either.
Anyway, that brings us to my topic du jour. As you may or may not have heard and read, we’re working on elevating the developers tools further. We’ll become more standard Visual Studio, standard Azure DevOps. This is all great news as it will allow X++ developers to use more of the existing tools out there that can be used for any standardized .NET languages or tools. The problem is not that we’ll be forcing people to use advanced tools they don’t know how to use. They can still choose to not use source control or build automation. I’m more worried about the people using all these new tools and not understanding them. What if in the future we start supporting Git? Will our support team be overwhelmed with people stuck on branching, merging, PRs, rebasing and all the great but complex features of decentralized source control? We’ve never dealt with situations where we “support” the technology (i.e. the tools are compatible) but we won’t support the user of that technology (sorry your production code got messed up, go get some training on Git branching and good luck to you on recovering your production environment). In the history of our product, we’ve never drawn a big line between technical compatibility but not supporting the usage of it. But we will have to. How about other areas, like PowerBI, PowerApps, etc.? Yes they are supported and will be integrated further, but will Dynamics 365 support answer your usage questions?
I’ve had frank discussions with developers (that I personally know), where I basically tell them “the fact you’re asking me these questions tells me you shouldn’t be doing this”. But that’s not an attitude we can broadly apply to our customer base.
So I ask YOU, dear audience. Where and how can we draw a line of supportability?
Oct 11, 2019 - Debugging woes with symbols: bug or feature?
Filed under: #daxmusings #bizappsI’ve struggled with this myself for a while during the betas of “AX7”. Sometimes, symbols aren’t loaded for your code and your breakpoints aren’t hit. It’s clear that the Dynamics 365 option “Only load symbols for your solution” has something to do with it, but still there’s strange behavior. It took me a few years at Microsoft for someone to explain the exact logic there. Since I’ve been sitting on this knowledge for a while and I’ve recently ran into some customer calls where debugging trouble was brought up, I realized it’s overdue for me to share this knowledge.
Summary: it’s in fact a feature, not a bug. But I would like to see this behavior changed assuming we don’t introduce performance regressions.
There’s a piece of compiler background information that is not well understood which is actually at the root of this problem. We all know there are two ways to compile your code: from the Dynamics 365 “Full build” menu, or from the project. The project build, if you right-click on your project, has two options: build and rebuild. Now, the “rebuild” feature does NOT do the same thing as the full build menu - and that is the crux of the issue here. Both build and rebuild from the project only compile the objects in your project. Rebuild will force a build of everything in your project but not the whole package it belongs to. To do this, our Visual Studio tools and the compiler make good use of netmodules for .NET assemblies. Think of a netmodule as a sub-assembly of an assembly, I guess.
Now, the point is this. The “load symbols only for your solution” option only loads the symbols of the binaries for the objects in your project - aka the netmodules. So when you do a full build from the Dynamics 365 menu, you actually HAVE NO symbols only for the objects in your project (only the full binary of the package). And as a result after doing a full build and debugging with the “symbols for solution only” option turned on, your breakpoints will NOT be hit due to the symbols not having loaded.
I think we should change this option to work more like “load symbols for the packages containing your solution’s objects” or something to that effect. We’ll have to see if that affects the performance for large packages in a significant way, since it will now load all the symbols for that package. That is ultimately why this feature was introduced (see? it’s a feature!). Worst case we may need a new option so you can use the old behavior or the more inclusive behavior…
I’d love to hear your thoughts on this, here or on Twitter @JorisdG.
Blog Links
Blog Post Collections
- The LLM Blogs
- Dynamics 365 (AX7) Dev Resources
- Dynamics AX 2012 Dev Resources
- Dynamics AX 2012 ALM/TFS
Recent Posts
-
GPT4-o1 Test Results
Read more... -
Small Language Models
Read more... -
Orchestration and Function Calling
Read more... -
From Text Prediction to Action
Read more... -
The Killer App
Read more...