User bio
404 bio not found
Member since Nov 6, 2015
Replies:

I'm not quite understanding the nature of the question.  

If you are asking  if banning Classmethods would block stored procedures then the answer is technically yes for the most part.  This would block any method based stored procedure as these have to be Classmethods. 

However there is still Query type stored procedures which are a different kind of class element.  That is a bit of a fudge as the method type ends up much like a ClassMethod anyway.  

Also there are Custom Query type query methods where you define Execute, Fetch, and Close methods each of which has to be a ClassMethod.
Of course this is all a bit procedureal as there is nothing beyond policy that would actually block the usage of ClassMethods in IRIS itself.  
As someone once said "It's important to know the rules so that you can break them properly."

I respectfully disagree with your overall premise that Classmethods are somehow bad and not to be used. ClassMethods, more commonly referred to as Static methods, are a part of every object-oriented language I have ever worked with. Let me expand on why this is, provide a perspective on why the approach suggested introduces issues, and finally propose an alternative.

The Indispensable Role of ClassMethods

It is vital to understand why ClassMethods are an absolute necessity in a well-designed object model. In InterSystems ObjectScript, a ClassMethod is not an architectural loophole; it is the natural, logical manager of a class template.

  • Clear Cognitive Scoping: It maintains a clean boundary by separating what an object does (instance methods) from how the system manages that type of object (ClassMethods).
  • Lifecycle and Persistence Control: You cannot ask an object to instantiate or retrieve itself. Operations like %New(), %OpenId(), or %DeleteId() must exist at the class level because the specific instance does not yet exist or is locked away in a database.
  • Deterministic Object-to-Object Operations: Operations that involve multiple instances—such as cloning an object or comparing two distinct objects—belong to the class, not a single instance. A ClassMethod acts as a privileged guardian, safely inspecting the internal properties of multiple instances at once without breaking encapsulation.
  • Utility Methods: While not directly an object issue, Classes and ClassMethods provide a centralized place to manage and access general purpose utility functions. Classes of utilities can be placed in there own packages for organization. A perfect example of this is the %SYSTEM.Status class that we have all likely dealt with.

The Downside of Banning ClassMethods: Constructor Injection Flaws

First, when testing the first approach should always be to test the way the code will be used IMHO. In most cases your Test environment will provide an implementation of all the resources that are to be referenced. This allows code to be fully tested exactly in the manner it will be executed in Production. Now we all know that this is not always possible. This is where Mocking the results is the appropriate response. That should be the fall back rather than the preferred design..
When developers rigidly ban ClassMethods in favor of constructor injection to achieve total mock isolation, they introduce what is known as Test-Induced Design Damage. This forces you to permanently disfigure your production architecture solely to satisfy a testing tool.

If you abandon a straightforward ClassMethod call and force dependency injection via %OnNew, you create immediate architectural problems across your codebase.

Impact on the Calling Class (MyOtherClass)

  • Architectural Pollution: The class is forced to maintain internal instance properties solely to hold references to stateless helper objects, cluttering the production model.
  • Constructor Bloat: The %OnNew constructor becomes completely overloaded with setup logic, requiring a safety valve of boilerplate code to handle both production defaults and incoming mock objects. The example in the post is for a single mocked method. Now apply this to a real application where you many have dozens of these methods to deal with.
  • Indirection Over Clarity: Readability, direct domain operations are replaced by an indirect layer of property-hopping, making the execution flow harder for a developer to follow at a glance.

Impact on the Dependency Class (MyClass)

  • Forced Statefulness: Naturally stateless, deterministic utility logic is forced to become instantiable, creating unnecessary memory allocation and object overhead in the production environment. 
  • Loss of Domain Authority: The class can no longer act as a centralized, top-down orchestrator for its own lifecycle, outsourcing its domain tasks to external objects.
  • File Proliferation: Developers are forced to write, track, and maintain an entirely separate mock class file (MockMyClass.cls) just to simulate a single piece of stateless behavior during a test.

The Pragmatic Alternative: Environment/Control Variables

Instead of corrupting your application's architecture to accommodate tests, a more reasonable approach treats the ClassMethod as a black box. If a specific class method truly interacts with an external, unmockable resource (like a live web service with no test environment of its own), the method itself can handle its testing context via an environment or process-level control variable.

This can be implemented in many ways including, but not limited to:

  • A Global (process-private) entry
  • A proerty in a control file
  • An OS level environment variables

objectscript implementation for MyClass.MyMethod

ClassMethod MyMethod() As %String
{
    // 1. Check if the process is currently in a testing context using a utility method
    If ##class(App.Environment).IsTesting() {
        // create a mock results as appropriate.  This can be done directly here or 
        // via a separate mock results management api.
        Set MockResult = ….
        Return MockResult
    }
    
    // 2. Real production logic lives safely underneath
    # do the real work production a Result

    Return Result
}

This pattern keeps the production architecture clean, preserves the logical purpose of the ClassMethod MyMethod(), and isolates the impact of mocking to that ClassMethod. The ability to mock for Unit Testing is managed with and by the method to be mocked. Control over use of Mocking is maintained external to the code being tested enabling easy setup of the Unit Testing code. Finally, the black-box nature of the MyClass.MyMethod() is restored.

Try logging into the System Management portal with that user, assuming the user has access to do so.  If you can log in.   Try to switch namespaces and see if you can see the list of namespaces.

One other thing to check is that your user or a role your user is part of has SQL Procedure access to %Library.RoutineMgr_StudioOpenDialog in %SYS

Certifications & Credly badges:
Rich has no Certifications & Credly badges yet.
Followers:
Following:
Rich has not followed anybody yet.