Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Ordering scripts by type or by system

Discussion in 'Scripting' started by Developer-6, Jul 31, 2023.

  1. Developer-6

    Developer-6

    Joined:
    Jul 26, 2023
    Posts:
    11
    We have a recurrent discussion between partners on how to approach code distribution in a Unity Project.

    The two options are as follows:

    Order scripts by system:
    Code (CSharp):
    1.  
    2. Assets/
    3. ├─ Scripts/
    4. │  ├─ PlayerSystem/
    5. │  │  ├─ PlayerManager.cs
    6. │  │  ├─ PlayerController.cs
    7. │  │  ├─ IPlayer.cs
    Or by type:
    Code (CSharp):
    1.  
    2. Assets/
    3. ├─ Scripts/
    4. │  ├─ Managers/
    5. │  │  ├─ PlayerManager.cs
    6. │  ├─ Interfaces/
    7. │  │  ├─ IPlayer.cs
    8. │  ├─ Controllers/
    9. │  │  ├─ PlayerController.cs
    Do you recommend any of the two options for big projects and big diverse teams?

    We assume we're going to order the whole project by type (Models, Scripts, Prefabs, ScriptableObjects, etc)
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,019
    By system! Just the way you structure code, really. You know you don‘t want to have a NetworkCollection in the same folder as a ParticleCollection, an EnemyCollection, a UserCollection and an ItemCollection, and a GuiButtonCollection. They may be collections but they are tied to specific subsystems (networking, vfx, AI, persistence, gameplay, gui).

    So, you naturally will divide these into Assembly Definitions for networking, vfx, AI, Persistence, Gameplay, Gui. Right? Because if you don‘t you will create a mess, otherwise nothing is technically stopping anyone from gameplay code to directly depend on Gui code, or Network code to directly depend on Vfx code, or even creating circular dependencies. You see that this would be an issue, I hope.

    The fact that you actually have this discussion let‘s me fear otherwise though. There should be no discussion about this. Educate the programmers who vote for the alternative, please!

    Namespaces should match the folders the scripts are in. A Namespace Company.Game.Player makes sense as does Company.Game.Player.Interfaces but not Company.Game.Interfaces unless you only store interfaces that truly need to have global scope (rare).

    Also, what‘s a „Manager“ script do? That is the worst category unless you have clearly defined purpose and boundaries for manager classes. We‘ve discussed that at length recently in another thread. ;)
     
    Last edited: Jul 31, 2023
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,019
    Also: check any decently complex package and see how they divided their code. It‘s mostly structured into systems, not by type.
     
    Developer-6, Bunny83 and spiney199 like this.
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,849
    I do both, with some stuff in between. The primary organisation is done via the major overarching systems, of which comprise their own folders/assembly definitions. Each of those is usually comprised of many sub-systems, making up their own folders.

    After that, it comes down to the individual sub-systems. Sometimes this means a folder for interfaces, utility classes, etc, but it's not always needed.
     
    Bunny83 likes this.
  5. Developer-6

    Developer-6

    Joined:
    Jul 26, 2023
    Posts:
    11
    Hey, I really agree on everything you said.
    The discussion comes from the necessity to categorize systems that are just links between other systems.
    As for the word Manager, we have a clear definition of it: "Single point of entry of a system without code flow initiative"
    So its just the public API for other systems to be used.

    So the background question that remains on my team is: how would you order systems that depend on other systems ? Would you showcase some kind of dependency on the project hierarchy order?

    Also, could you pass the link of the thread you're referring to?
     
  6. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    284
    I recently broke up my project into a lot of individual assemblies. The first thing I did was to clearly define all of my dependencies. Unfortunately I don't know of a good way to automatically generate a nice visual dependency graph, so I did it the hard way. I pulled each file one by one into an empty project and made manual notes of every interdependency. I drew them all up on my own charts with tiny sticky notes I could move around and draw dependency lines between them. This actually helped me refine some rough edges in the end. I thought I had a good overview of my own code in my head, and had my scripts organized pretty well in that way, but forcing myself to explicitly define all dependencies and break up each module into its own assembly forced some things to the surface that I wouldn't have caught with just a general overview in my head, even though I wrote every line of it. To define those dependencies within the project you would put each module that can be logically separated into its own assembly in an assembly definition. You define dependency relationships with the asmdef and can see them there. My folder structure is pretty flat beyond that, except for having Editor, Runtime, and Core / Unity folders underneath Runtime. Some of my code has no Unity dependencies and so I keep it in a Core directory. Beyond that, each assembly is in its own folder in one of those. After having done all of that it's clear that everything will naturally organize itself by module and dependencies between modules, not by any other concept of type. When you have a visual image of your dependency graph that you can see, and easily explain each module or subsystem, then you can visualize which modules can be removed without breaking something, and which sit closer to the root of a dependency hierarchy, and cannot be removed if there are more dependent modules that rely on them.

    That being said, there are a few modules that represent a sort of bringing it all together of all other modules into a complete package. So, there are a few root modules that many others depend on, then there is a sort of branching tree from low level to high level of more and more complex systems that depend on those lower level modules. So, you have kind of a tree of subsystems growing up in layers that are dependent on the lower levels, but theoretically a whole branch of this tree could be pruned, without affecting all systems, if you truly didn't want that branch of features, or are just trimming off the higher level features. But, then at the end I have a few that are highly dependent on the entire tree to show the whole system, including all submodules, being used as intended. These highly dependent modules live at the root of my application's composition graph and serve as an example of how to start defining a particular app that depends on everything else. So, above the more loosely defined branches of the dependency tree that make up major features, there is a sort of application root that then has dependency lines that touch the whole canopy of the tree to make use of all the systems to start creating a real app with them.
     
    Last edited: Jul 31, 2023
    Developer-6 likes this.