The Now Platform® Washington DC release is live. Watch now!

Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
coryseering
ServiceNow Employee
ServiceNow Employee

Scoped Applications are a fun topic for me. I was able to contribute during the development of the Scoped App model, and since then I've written a lot of small Scoped Apps personally, as well as contributed to the Studio- a Scoped Application that's like an IDE for building Scoped Applications (read more about that here).

What is a scope?

Generally speaking, a scope is like a namespace for your application. Everything in your application falls under this namespace. It separates your classes, tables, and UI components from everyone else's; it gives you control over their names, how they can be accessed or extended by others, and keeps your code from accidentally polluting the global namespace. A good discussion of these benefits can be found here.

Technically speaking, scopes are a bit more complex than that. A scope isn't just a namespace, it's also a record in a table (sys_scope). All of the files that are part of your application have a reference to this record- or to one of the tables which extend it (sys_app and sys_store_app). That's not the true root (sys_package is) but it's as top-level as you ever need to go.

All files in your Scoped Application will have a reference to your sys_scope record. That's because every record in your application will be in a table that extends sys_metadata, or will be a table definition (a sys_db_object record and/or sys_dictionary record) which itself extends sys_metadata. In the sys_metadata table, there is a reference field to sys_scope, and this ties your whole app together.

The global scope is also a scope- you can check that out too. It's a sys_scope record, where the scope name is 'global'.

Screen Shot 2015-11-18 at 10.12.49 AM.PNG

Everything created pre-Fuji is pretty much a part of the same legacy globally-scoped application. Most of the legacy stuff defaults to being open to all app scopes to use. It's also possible to create new Scoped Applications where the scope is 'global'. I don't really see much of a reason to do that, though.

When checking things like cross-scope access protections, global is "just another scope". If you create a Script Include in your Scoped App that is "Accessible from: This application scope only", then a script running in global cannot access it. Only scripts in your same scope will be able to make use of it, which means you can make changes in each release without worrying that you might be breaking something else that depends on it. Of course- it cuts both ways. If you make the include accessible to other scopes- like you would do for an API, or some common utility script that you think will be useful, then you should be just as careful as ever about making breaking changes.

Screen Shot 2015-11-18 at 10.16.24 AM.PNG

Differences between Scoped Apps and Global Apps

Update Sets

Global Apps are exclusively tracked in Update Sets. When you want to start work on a new release, you have to create a new, clean Update Set, switch into it, and be meticulous about switching out of it when making non-relevant updates, and switching back into it again when you're done. You have to close the set, transfer it, preview it, fix any problems, and apply it.

Scoped Apps can be tracked in Update Sets- they can even be moved around via Update Set, but that's a really legacy way of doing it. We automatically create an Update Set for each scoped app, and switch into it whenever you start editing that app. It's generally something you can ignore. Global Apps use Update Sets as a system of record for changes to an instance, and for moving a series of changes between instances. Scoped Apps are always complete- they represent an "end state" instead of "a series of changes to make". It's not impossible to do the same thing with Update Sets, but anyone who's had to go through every single record they believe constitutes their application and "touch" them to get one complete Update Set out of it knows how annoying that can be. I know it- I've done a few times, and I consider it the nuclear option for fixing "my change isn't coming across".

Scoped Apps are packaged up complete, with all relevant records to install on a new instance that has never seen the app before, or update an existing instance where an old version is installed. Even if you choose to Publish to an Update Set, the entire app will be copied in, not just the changes you've made since the last time you published. When you publish to the repo (either via "Make App available on other instances" or "Publish to Store"), the app is packaged up, stored on the repo, and (potentially) made available to all of your organizations instances to download and install or upgrade. Published apps always represent an end-state, not a series of changes to be made.

Install and Uninstall

Installing a scoped app is generally as easy as going to the Applications page, switching to the Downloads tab, and clicking the Install button. It's an actual installation, versus applying an Update Set, which is how a legacy application is installed.

Screen Shot 2015-11-18 at 10.30.01 AM.PNG

Global applications can't really be "uninstalled". Since nothing ties your application together into one cohesive app, it's difficult to tell where your "loaner approval" ends and CMDB and Approvals begin. You can back out Update Sets in reverse order, until you've removed the one the one that brought in your changes, but that's neither fun nor easy. You could also comb through all of the references in your Update Sets to find the individual files, or trace code paths and refer to documentation, but that's harder than it should be. Scoped Apps are uninstallable. You can do it right from the sys_store_app record for that app. I think it's two clicks and a confirmation (you have to manually type "uninstall"). The "everything is packaged together" aspect makes it *vastly* easier to install and uninstall.

Screen Shot 2015-11-18 at 10.35.22 AM.PNG

Public and Private

Global Apps live together, but not always harmoniously. When everything is a public API, nothing is reliable, or everything must be static. If you write a Script Include with 10 useful methods that get used in a hundred different places, changes to those methods can have far-reaching and unintended consequences. You had to do extensive searching to see if any of the server-side script fields that could potentially access that include actually do, and if your change will adversely affect them (not to mention Filters, default dictionary values, forgotten scheduled jobs, etc).

Scoped Apps allow you to set a Script Include private- truly private, accessible only to your application. You can make a public, static API (or one that that at least changes infrequently) while updating the behind-the-scenes private stuff with weekly releases. You can also name it anything you like- a scoped Script Include is automatically namespaced to your scope. Your JSONUtil include can't conflict with some else's, nor with a global one. You can split your utilities from the rest of your code and update them separately.

Screen Shot 2015-11-18 at 10.32.17 AM.PNG

It's possible to get most of the benefits of Scoped Apps with the legacy global model- you just have to try hard. It's not easy, and you have to be meticulous. The legacy system promotes interdependence; Scoped Apps promote interfacing. In general, I think we'll all find that route leads to cleaner code, easier updates, and less frequent behavioral anomalies (my new favorite term for 'bugs').

Philosophy of Scoped Apps

This is my understanding of the philosophy of Scoped Apps. I had a small part in the platform side, and I don't speak for everyone, but here's how I see it.

  • Do not break system functionality.
  • Do not break other apps.
  • Do not hog resources.
  • Be self-contained, with clear dependencies where necessary.
  • It's easier to start locked-down and gradually open up than the reverse.

     

Almost everything we've done with Scoped Apps is to address or encourage those points. For example, you cannot make a field on someone else's table disabled or read-only. If they have marked the table extendable, then you can extend it and make all the inherited fields read-only if you wish. That is one way we try to ensure that apps don't interfere with each other. Another example: GlideAjax calls from scoped Client Scripts must be asynchronous. A popular table like Incident is likely to attract many Scoped Applications, adding Client Scripts and validations and nice conveniences. Since you (the app developer) aren't necessarily aware of the exact environment your Client Script is running in- especially with regard to other Scoped Apps installed alongside yours- it's one way we can make sure that the user isn't stuck waiting for multiple round-trip GlideAjax calls to complete when they attempt to submit a form. In the legacy system, the administrator would need to keep tabs on that.

By adhering to the above principles, multiple Scoped Apps, from different vendors who may never have even known about each other, can coexist on the same system. You can release as frequently as you like, and so long as you follow best practices around you public-facing interfaces, you can be much more sure that your release can't break someone else's app, nor their releases break yours.

That last point is important too- it's easier to open something that used to be closed than it is to close something that used to be open. We spent a lot of time and effort on determining which APIs are exposed to Scoped Apps, and which ones aren't. We fully expect to continue adding to the APIs that are available over time. If we left out something near and dear to you, let us know.

Choosing the right model

Almost everything that you want to build can be done with Scoped Apps. However, sometimes it is more convenient or appropriate to use the legacy model. If you require access to an API that isn't available to Scoped Applications, then you may need to use the legacy model. If your processes are dependent on moving Update Sets around, the legacy model might be right for you. If you need to change the core functionality of a legacy application, then you need to do it in the legacy model.

When you are creating new functionality, or extending an existing application, then a Scoped App is probably the best choice.

Upcoming features

In Geneva, we're releasing the Studio. There's already been a couple of posts about it, and it's honestly the thing I am most excited about. I contributed heavily there, and I I hope we get a lot of feedback about to make it better in Helsinki and beyond. It also has an awesome Code Search tool which has made my life much easier these past several months. In Helsinki, we hope to have some more advanced collaborative development tools, as well as some advancements in the design-time and run-time permission model. Also, Code Search will be broken out into a separate, extendable Scoped App, accessible via a REST API. I wrote this, and I look forward to seeing what you do with it.

We aren't done iterating on the Scoped App model. As it gets wider adoption and the feedback comes pouring in, expect the experience to continually improve.

7 Comments