How to Make Better Code Assets for the Asset Store?

@longroadhwy asked if the Asset Store had a “Design for sales and success: making integration easy with extensible unity assets” type of document. Since I’m not aware of any, I thought it might be helpful to crowdsource some unofficial suggestions.

I’m particularly interested in your thoughts on the Extensibility section. Frankly the rest is mostly window dressing, but extensibility is a fundamental design factor that has a big impact on how easily customers can integrate your code assets into their projects.

To kick it off:

Follow Unity’s Submission Guidelines for code assets. [hpjohn]

Documentation
Comment your code for automatic documentation generation using a tool such as Doxygen. MonoDevelop and Visual Studio make it easy. Just type “///” above a declaration, and the editor will paste in a template to fill in.

At the very least, declare each class in a separate file, and document the purpose of each one. Ideally, also add comments for each public class, property, and variable declaration.

If the purpose of a serialized variable is not obvious or has caveats, use the [tooltip] attribute for MonoBehaviours and ScriptableObjects that use the default inspector.

Document changes when updating. [hpjohn] Keep a running change log from the very first release of the product. API changes and feature deprecations in particular are critical. [longroadhwy] If upgrading requires the customer to take special steps, point those out in an upgrading document (e.g., upgrading.txt). [syscrusher]

Provide documentation in an open format such as PDF or text that customers can open easily on any platform. [syscrusher]

Offer local installation of documentation. Online documentation is useful but usually only reflects the most current version. If a customer’s project is locked to a particular version of product, the customer should have documentation that matches that version. [longroadhwy]

Explicitly list which platforms were tested with the code asset (e.g., tested with Windows, Mac OS/X, iOS, Android and Linux). Also include appropriate OS version numbers if required. [longroadhwy]

This post also has a good discussion on code asset documentation.

Folders & Files
Put your code asset entirely under one folder when possible. Some exceptions, such as gizmo icons and plugin DLLs, must be in other special folders. Consider putting your scripts in Plugins, or at least make sure they work correct if the user moves them intno Plugins. See Where to Install Your Assets for a comprehensive answer. [based on tips from hippocoder, guavaman, SonicBloomEric, makeshiftwings]

Avoid hard-coded paths whenever possible.

Keep your file metadata consistent. Avoid deleting files and re-adding them by dropping them into the Projects view; this will generate new metadata files.

Put example and supplemental files in a separate folder that customers can delete if they want to strip down their project. Don’t intersperse them with files that are necessary for your product to operate.

If providing precompiled DLLs with the option to import source code from a separate package, bear in mind that MonoBehaviour and ScriptableObject declarations will have different GUIDs in the DLL versus source code. Consider insulating the customer from these GUIDs with wrapper scripts so they can switch between DLL and source without losing script references.

Code Organization
Don’t Repeat Yourself. If you do the same thing twice or more, consider making a static method or class to do it for you. [LaneFox]

Use namespaces! [everyone :)]

Prevent other scripts from breaking your code asset by specifying namespaces explicitly when using common class names. Assume that the customer or another code asset may define a common class name in the global namespace. For example, your code may have a “using UnityEngine.UI” statement and then declare a Button variable that’s implicitly in the UnityEngine.UI namespace. However, if the customer defines a Button class in the global namespace, your code will break if it tries to reference the wrong Button type. New Unity users will often define their own classes with these names in the global namespace, which will break your asset unless you specify the correct namespace: Text, Button, Camera, Action.

If you don’t want to litter your code with explicit UnityEngine.UI.Button’s, declare it explicitly in your using section: “using Button = UnityEngine.UI.Button;”. [flaminghairball] Or put your using statements inside your namespace declaration. This will override any classes of the same name in the global namespace: [guavaman]

using UnityEngine;

namespace MyNamespace {
    // These will take precedence over any global classes or any classes inside using statements that are outside the namespace declaration.
    using MyOtherNamespace;
    using UnityEngine.UI;
    ...

Consider providing helper classes to simplify the customer’s access to the API.

Don’t use shader keywords in shaders or materials unless you really, really need them, due to Unity’s hardcoded limit. [makeshiftwings]

And fix all compiler warnings. [makeshiftwings] Your asset should compile in all supported versions of Unity without any warnings.

Extensibility
Support extensibility without requiring the customer to directly modify source code, since changes will be lost when the customer updates to a new version of the code asset. (It can also be a support nightmare to provide technical support for scripts that customers have been forced to modify and possibly add unintentional side effects.)

Use UnityEvents or the Unity event system, virtual members, C# interfaces, and/or C# events and delegates to make your product extensible.

Consider making Awake, Start, OnEnable, OnDisable, and OnDestroy methods virtual so subclasses can do extra things in them.

Try to make modules as self-sustaining as possible. [LaneFox] This allows customers to re-use modules or use them in new ways without impacting other modules in your code asset.

Build your asset so it can handle alternative input systems (e.g. InControl, Rewired, etc.). [longroadhwy] It doesn’t have to provide support for these input systems; just don’t make it hard for customers to add support. For example, use a delegate or other kind of abstraction instead of calling Unity’s Input class directly.

Third Party Integration
If your code asset integrates with another product, specify which party maintains the integration and which versions of each are supported by the integration. [longroadhwy]

Debugging, Console, & Error Handling
Do not submit a product to the Asset Store that generates compile-time warnings.

Check Debug.isDebugBuild before logging any debug messages.

Provide an object reference as the second parameter to Debug.Log* methods to make it easier for the customer to identify the source of the message.

Consider adding ample verbose logging to help the customer debug issues and know what’s going on under the hood.

Consider providing an option to turn debug messages on and off, or to specify a desired verbosity level. Don’t clutter the console with info-level messages unless the customer has requested them.

Catch exceptions and handle or report them gracefully. [LaneFox]

Consider using unit testing. [LaneFox]

Coding Style
In the interest of avoiding a religious war, let’s tread lightly on this topic if at all. Please just be consistent within your own code, and be aware of the different styles adopted by Unity and Microsoft – e.g., Unity uses camelCase for public properties, Microsoft uses PascalCase.

Asset Store
As of June 20, 2016, the Asset Store no longer allows duplicate product names. Before submitting to the Asset Store, make sure your chosen name isn’t already taken.

Submit your asset in the right category. If you require a per-seat license, make sure it’s in Editor Extensions.

Only attach asset labels to assets in your package if you think they’ll be helpful to customers using your product. Asset labels are no longer used for searches in the Asset Store. Instead, set the product’s meta data on the publisher page. Here are notes about searches and meta data:

  • You do not need to include plurals. They are automatically added to the extent that they are dictionary words.
  • Package name is included as keywords.
  • Package description is included as keywords.
  • Category is included as keyword.

Make sure your support email and web page URL work.

18 Likes

Thanks for the Like, @zombiegorilla . I’m surprised no one’s actually posted any more suggestions yet. Maybe I would’ve had more takers if I’d titled the thread something like “Pet Peeves With Code-Based Asset Store Plugins”. The items above are my complaint/wish list as an Asset Store customer, things like:

  • Comment your code
  • Don’t leave in compiler warnings
  • Don’t use hard-coded paths, etc.

Does anyone else have anything they wish more Asset Store developers would do?

1 Like

Or “You won’t believe these 10 things that developers forget to do!”

Obviously, make sure you’re following Unitys guidelines at the very least
https://unity3d.com/asset-store/sell-assets/submission-guidelines

Documenting changes when updating

1 Like

Well, you did a good job highlighting the majority of issues really.

I’m no expert, but I agree with extendability being a high priority. When you have something easily extensible then you have a good easy to read and use product. It depends greatly on your asset type but you want people to be able to get in and add things painlessly, and arbitrary (and/or undocumented) dependencies inside your code make that difficult.

  • Try to make modules inside your code as self sustaining as possible.
  • Reduce the possibility of failure everywhere, use Unit testing if you can. Catch exceptions.
  • If you do the same thing twice or more, consider making a static method or class to do it for you.

What are the “best” ways to make it extensible? I put that in quotes because every situation is going to be different, but perhaps some general ideas? These might be useful:

  • Virtual Awake and Start methods. This would make it easier to create a subclass that does a little extra work in Awake or Start.
  • Virtual public accessors for tweakable properties.
  • Liberal use of UnityEvent? Unless you’re invoking those UnityEvents every frame, it shouldn’t be a performance concern.

I think for the most part those fall under general “good coding practice.” We can only hope that all of us developers are striving to follow good coding practice. I strongly agree that a module shouldn’t fail internally. For example, if a method expects a non-null argument and you pass it null, the module itself shouldn’t break. But should it entirely mask the exception (possibly logging a warning), or is there ever a case where it should it handle it gracefully internally and then rethrow it?

EDIT: Scratch that thought about rethrowing. The submission guidelines state:

Graceful handling of errors: Your asset must provide useful warnings to the user if he or she does something wrong. Under no circumstances should your extension throw null reference exceptions, unclear error messages or warnings. Remember that your code will be included in other people’s project and too many warnings from 3rd party contributors may clutter up important errors or warnings in their own code. Error messages must be in the form of a message / dialog or inline warning and explain how to fix the problem.

Thanks to both contributors so far! I put your additions into the first post.

I also added this one, which can be a real pain:

Specify namespaces explicitly with common class names. Assume that the customer or another product may define a common class name in the global namespace. For example, your code may have a “using UnityEngine.UI” statement and then declare a Button variable that’s implicitly in the UnityEngine.UI namespace. However, if the customer defines a Button class in the global namespace, your code will break if it tries to reference the wrong Button type.

There are some awesome, highly-reviewed, and otherwise nicely-written code assets that fail to compile because a different code asset defined Button, Text, Editor, or other common names in the global namespace. There’s no easier way to get a 1 star review than for a customer to import an asset and no longer be able to play their scenes because Unity can’t finish compilation. Even though it’s “not your fault,” you’ll still get angry, off-the-cuff reviews saying, “Don’t buy this! It will break your project!”

I would love to get more thoughts on the best ways to make code assets extensible.

1 Like

(1) Running change log.

Basically keep a running change log from the very first release of the product. If changes are only from release to release (via unity asset store) it is easy to miss important changes. In particular related to API changes this is critical.

FeatureX has been deprecated. API additions or deletions.

(2) Local installation of the documentation.

On-line documentation is useful but usually only reflects the most current version of the software. If you project is locked to particular version of the software it nice to have the documentation that matches the current state.

(3) Platforms Supported/Tested against

“Asset XYZ works with Unity!” Is not very helpful. It is nice to be explicit what platforms were tested with the particular asset. For example This asset was tested with Windows, Mac OS/X, iOS, Android and Linux. Also appropriate versions of the OS if required.

3 Likes

I posted a thread about a month regarding ridiculous amount of compiler warnings generated by asset store scripts:

I agree strongly with what you say in this thread: "Do not submit a product to the Asset Store that generates compile-time warnings."

Also another thing that keeps happening is asset store items are including the standard assets scripts along with the asset store item. For example: I’ve downloaded numerous asset store items that contain the “MouseLook.cs” or “FPSInputController.js”. This is part of the standard assets. This poses problems when installing the asset because the n Unity will complain that there are duplicate files with the same name. I suggest to add a rule to require the asset store seller to rename these to something different, or not include them in the asset. (Normally they are included in the demo folder of the asset)

Not to name any assets, but here is what happens:


The asset store item can’t compile. You have to have the know-how to go into the asset folder and fix it yourself. This has happened a few times to me.

3 Likes

This problem seems to be less common nowadays, but it’s an annoyance of mine, too.

I’d prefer if developers kept these scripts in their original locations (e.g., Standard Assets) with their original metadata. This way they won’t be duplicated.

Does anyone else have any insight into this problem? Before I add this to the first post, I’d like to see if we can get a consensus on the best way to handle it.

2 Likes

A sidenote on this - if you hate the idea of cluttering up your code with UnityEngine.UI.Button everywhere, you can also force the namespace reference like so:

using System;
using UnityEngine;
//etc
using Button = UnityEngine.UI.Button;

That way you’re still explicitly advertising which button class you’re referencing, but you still get nice compact code.

5 Likes

Integration:

Officially supported integrations.

If asset Y says it is integrated with assets A, B, and C. I would expect the asset Y is responsible for maintaining the integration. Of course it could be that asset C could be responsible for maintaining the integration with asset Y.

It would be nice to have a clear indication of which asset is responsible for maintaining the integration.

There are many one time integrations that are used as examples of what can be done integrating asset Y with asset K for example. But that is not officially supported.

3 Likes

Personally, I feel the best way is for every single script which is included with the asset, be assigned a unique name which relates to the asset. Here is an example of how MeshBaker names their scripts:
MB2_TextureBakeResults.cs.

This does two good things: It relates the script to MB, which stands for MeshBaker.
It also includes the version, so if you update the asset, you can clearly see the version of the script. In this example the version of the script is 2. If they had a version 3 of the asset, the file name would be MB3_TextureBakeResults.cs.

I don’t think this can be enforced, but I think this is very good practice.

Sounds nasty. I don’t want to break my entire project by changing script names every time its updated. Better to simply include everything in a asset inside its own namespace. Using something related to the brand name is great. How many people are going to have a name collision with BoredMormonGames.AwesomeAsset.Button?

1 Like

I just want people to learn2love Plugins folder. Final IK does this. Means I get source without bloated compile times.

3 Likes

I have to admit I’m in BoredMormon’s camp on this one. I definitely agree with you that developers should make their names unique. To me, namespaces seem like the best approach. Anyone else want to weigh in?

I’ve been thinking about this recently. If I could go back in time three years, I would probably put the Dialogue System’s huge amount of editor code in Plugins rather than providing precompiled DLLs and the source code in a separate unitypackage.

How would you recommend structuring the product? Everything inside a subfolder of Plugins?

Plugins
BoredMormonGames
AwesomeAsset
ExampleScenes
Prefabs
Scripts
Editor
Textures

Or only code in Plugins?

BoredMormonGames
AwesomeAsset
ExampleScenes
Prefabs
Textures
Plugins
BoredMormonGames
AwesomeAsset
Scripts
Editor

I don’t really see any value in splitting it up like the latter example, but maybe I’m missing something.

Are there any arguments against Plugins?

I don’t have a comment on structure so long as it works and asset authors can agree. Regarding naming scripts, I don’t see how that helps but namespaces definitely 100% do. There’s a number of really sloppy developers that just piss me off. All assets you buy that contain code really, really need namespaces!

I think its a bit like getting a tv service and all it does is dominate your own choices. That would be annoying!

1 Like

@hippocoder - Do you (or anyone else) have any suggestions on the following?

My tidiness impulse wants me to put the entire code asset under Plugins.

The problem is supporting third party applications such as providing PlayMaker action scripts. Since PlayMaker isn’t in Plugins, I’d have to keep these scripts outside of Plugins so they’ll compile in the correct phase.

Any suggestions on how to handle this?

Exhuming this thread to add clarifications on searching that we just received from the Asset Store staff:

Asset Store
Submit your asset in the right category. If you require a per-seat license, make sure it’s in Editor Extensions.

Only attach asset labels to the assets in your package if you think they’ll be helpful to customers using your product. Asset labels are no longer used for searches in the Asset Store. Instead, set the product’s meta data on the publisher page. Here are notes about searches and meta data:

  • You do not need to include plurals. They are automatically added to the extent that they are dictionary words.
  • Package name is included as keywords.
  • Package description is included as keywords.
  • Category is included as keyword.

Make sure your support email and web page URL work.

(This is also now in the first post.)

This is a nice addition from the asset store!

Another one is build your asset so it can handle alternative input systems (e.g. incontrol, rewired, etc.). Not sure how I missed this originally.

1 Like

The following behavior appears to have been changed as of Unity 5.2.2 (according to this), but it’s still worth noting as many assets will want to support back to versions prior to 5.2.2.

In Unity 4.x - 5.2.1, “Editor” folders placed in any subfolder underneath Plugins deeper than Plugins/Editor will not compile in the editor assembly and instead will be compiled in the main assembly throwing errors and preventing compilation. Because of this behavior, it makes having your whole project under one folder impossible if you also need editor scripts. If you do, they’d have to be stored in a separate location, either outside plugins or in Plugins/Editor.

Another way of dealing with this problem is to put your using statements inside your namespace declaration. This will override any classes of the same name in the global namespace. It’s a lot cleaner than typing the fully qualified name every time, and personally I like it better than declaring each class individually.

using UnityEngine;

namespace MyNamespace {

    // These will take precedence over any global classes or any classes inside using statements that are outside the namespace declaration.
    using MyOtherNamespace;
    using UnityEngine.UI;

    public class MyClass : MonoBehaviour {

        Player myPlayer; // exists in MyOtherNamespace

        void SomeFunction() {
            myPlayer.DoSomething(); // will not cause a compiler error if the user creates a Player class in the global or any other namespace.
            Button button = GetComponent<Button>(); // will not cause a compiler error if the user creates a Button class in the global or any other namespace.
        }
    }
}
1 Like