Jump to content
  • Advertisement
thatguyiam

Advice Scalable development methodologies for small teams and one man indies

Recommended Posts

For one man indies and small teams, in unity in particular - but general answers are very welcome - what are the most worthwhile development methodologies and architectural patterns worth investing your effort into. I would like to write decent, maintainable and scalable code, but I also want to work fast. In the past I've been bogged down in process, and at the moment for my current project I'm taking inspriation from Johnathon Blow and just not overthinking or optimizing in any sense before its needed. I am certainly getting quicker output but at the same time I realize that as my projects scale I will get be more likely to get bogged down, especially with no testing or other techniques to catch regressions. So avoiding rigid bindings and singletons might be advisable. I've considered dependency injection frameworks / inversion of control containers such as zenject. The code seems ugly to me and I cant see it being a fast process. I've heard mention of essentially using the unity interface for dependency injection, but I'm not sure I comprehend.

What process would you recommend? tdd? di? testing after the fact?

what are good ways to write clean, modular, scalable code quickly with strategies to catch regressions.

Any advice is welcome and appreciated.

Share this post


Link to post
Share on other sites
Advertisement

Try out TDD, but beware that it has a larger learning curve than it initially seems to.  You will most likely do things in a cumbersome way for a while as you get used to it, and you'll most likely shoot yourself in the foot a few times with it like I have.

Try to avoid dependency injection frameworks.  They're just one more thing that can go wrong.  It's likely that you will be able to use TDD in a way that does not require dependency injection frameworks at all.  If you get to the point where you're methodically using TDD style you will be building your program bottom-up and can avoid unwanted coupling from the start.

Make things simple.  Single responsibility principle is extremely important.  Don't try to make everything an interface to appease the mythical DI gods; usually one function that does exactly what you want to do is the only one that ever needs to fulfill that interface.

For Unity, attempt to write as much of your code as possible OUTSIDE of MonoBehaviours.  MonoBehaviours have unwanted dependencies and horrid initialization restrictions compared to plain old C# classes.  It's easier to test code if it doesn't require MonoBehaviour/GameObject baggage.

Share this post


Link to post
Share on other sites

@Nypyren  Thanks for your input. I understand the value of TDD, especially in application development. The whole fact you're writing code to satisfy the contract you create with the tests should provide full covereage and result in loosely coupled classes. My main concern with test first is that I've seen quite a few competent developers recently discuss disliking tdd first, even test advocates, as they consider it to impede rapid iteration of an evolving code base. I've seen some discuss data oriented programming and some suggest you should produce tests after writing hthe code merely to catch regressions. But running a suite of unit and integration tests every build would also get annoying, I suppose it would be acceptable in unity as I mainly run in editor and then build when im ready to check some things anyway.

I would agree wth srp, It's the most vital of the solid principles. Really the only solid principle I'm not adhering to is dependency inversion, which a lot of people suggest is the most important one, at least following srp/seperation of concerns stuff. But there are other ways to achieve dependency inversion, such as service locator etc. ANy advice on that matter is also appreciated, I want to be good at my craft but also start finishing things for a change.

At least in application development I've heard that getting used to tdd makes you faster and cleaner, but I've not really found that (though my experience is limited). I also am aware of the fact that output is traditionally very slow. Mythical man month 10 lines a day stuff (though obviously skewed by working on large bases and removing lines) the talk by Johnathon Blow where he discusses  how to achieve  great enough output to be able to deliver on your indie games really change my mind on a few things, though I haven't really filled in the blanks yet.

I make extensive use of couroutines and when the choesion is high enough I would favour just using a monobehaviour, but I'll take that into consideration. I've read that af ew times lately actually, I'll do my best to avoid monobehaviour and scriptable objects when its unwanted.

At the moment I satisfy my dependencies mostly using getcomponent or passing in the inspector. Not especially convenient for designers I iamginge, given the hierarchy thus has specific structures required. I completely avoid Find searches, though they should be fast enough on projects of this scale, I don't use them for other clear reasons.

For my current project I'm using a few high level singletons. GameManager, AudioManager, etc. It's not so far been a problem but it could be done better, but I'm not sure what would be better without di.

Any more suggestions on methodologies and regression catching strategies is greatly appreciated.

ps. it annoys me that empty objects I use for maintaining structure and convenience in the hierarchy have transforms.

Share this post


Link to post
Share on other sites
8 hours ago, thatguyiam said:

I've seen quite a few competent developers recently discuss disliking tdd first, even test advocates, as they consider it to impede rapid iteration of an evolving code base.

It does both.

TDD is amazing for stuff that has a long tail.  I've used it in development for server features and code with a long-term support.

Automated tests ensure permanence. They ensure that if you modify the behavior you get test failures, which in turn prevent accidentally changing your behavior.  For libraries and for long-running code that must be supported for years, this is great.  The initial costs are offset by many years of reduced maintenance cost. 

Since it ensures permanence, that means it works against rapid iteration. For game code you intend to throw away on completion, where the code should generally be fluid and changes frequently, it is not so great.  Instead of having a collection of automated tests that remain green as you change implementation details, when you are changing visible behavior then every change requires changing a test. 

Automated tests also have a cost in time and effort.  There have been several studies on it. TDD is usually the cheapest, at about 1:1 cost for developing the main code plus developing the tests.  Adding tests immediately after writing increases the cost slightly since some things need to be modified, and adding tests to established systems tends to have significantly higher costs since parts of the system must be retooled or adapted.  So if you are going to be implementing tests, TDD is the most cost-efficient way to do it.

For your short lived code in Unity or similar engines, TDD is a poor decision from a business standpoint.  The extra investment won't be recovered over time like it would be with a long-lived project.  For a long-term system that needs to be resilient against change under maintenence, TDD is wonderful.

8 hours ago, thatguyiam said:

I make extensive use of couroutines and...


Co-routines are an easy way to introduce delayed processing without violating Unity's model where the scripts follow a reliable linear flow.  You can use the full suite of multiprocessing/multithreading code through the .net runtime, but it opens the standard sets of difficulty with parallel code. It adds about an order of magnitude of complexity to your bugs, which is a great reason for the game engine designers to direct beginner and intermediate developers away from it. 

8 hours ago, thatguyiam said:

Really the only solid principle I'm not adhering to is dependency inversion, which a lot of people suggest is the most important one

Dependency inversion is extremely important when you have many subclasses, when you have a bunch of code that gives slight variations on the implementation details but provides a common interface.

Dependency inversion usually isn't necessary if you have no subclasses, if you have only one type of thing and never need variations under a common interface.

Unity scripts already do this in many ways, such as following the GameObject interfaces, or the Component interface, Joint that is implemented by assorted hinges and springs, Renderer that applies to MeshRenderer and CanvasRenderer and BillboardRenderer and ParticleRenderer and other visual things.  For these situations you only need to know the interface, the specific type of object usually doesn't matter.

Many Unity scripts I've written over the years do not need additional interfaces.  Some advanced systems do, especially systems where you have a bunch of interchangeable parts, but when you implement them they usually don't grow from MonoBehaviour.

9 hours ago, thatguyiam said:

ps. it annoys me that empty objects I use for maintaining structure and convenience in the hierarchy have transforms.

It is a design decision, but I think a good one.  Since nearly everything else requires exactly one transform, building it directly into the object allows for space savings. Many items built for maintenance as you describe get converted into prefabs, and then you really want the GameObjects that provide structure to also have the transform.

In non-trivial worlds you constantly add and remove scenes, which means adding a GameObject container, positioning it appropriately, and loading the new scene into it.  The position is important to make the world continuous, and the container part is necessary so it can be cleanly unloaded later.

A few heavily scripted items may live inside a utility GameObject, but they're a tiny number.  Generally I've seen one single game object with a unique name and layer living at the root layer that serves as the service locator.  Find that object and use GetComponent<>() to pull off whatever service you need.

The extremely rare inconvenience is far outweighed by the large benefit to every other object in the game world.

21 hours ago, thatguyiam said:

write clean, modular, scalable code quickly

The common, standard answers apply.

Write with namespaces so one system's code doesn't interfere with another system's code, Unity does not wrap code in namespaces by default. Configure Unity's files for scenes and asset information are text based rather binary, so they can be more easily merged and integrated.  There are two models to version control, one that restricts access and locks by default, another that merges when posting and is unlocked by default; you can save headaches if you configure version control to make the files (.asset, .scene, .meta, etc.) automatically lock on checkout. Divide your systems into small enough chunks that pieces can be worked on concurrently, such as designers editing prefabs rather than editing scenes, code broken into sufficiently small subsystems, etc.

Writing clean code is basically the same regardless of the tool you're using.  It should be well named, have uniform naming standards and uniform conventions, and otherwise follow standard coding guidelines and practices.

Share this post


Link to post
Share on other sites
13 hours ago, thatguyiam said:

My main concern with test first is that I've seen quite a few competent developers recently discuss disliking tdd first, even test advocates, as they consider it to impede rapid iteration of an evolving code base. I've seen some discuss data oriented programming and some suggest you should produce tests after writing hthe code merely to catch regressions. But running a suite of unit and integration tests every build would also get annoying, I suppose it would be acceptable in unity as I mainly run in editor and then build when im ready to check some things anyway.

My experience is:

TDD slows you down because you spend time up front writing your test, then writing your code, then testing, then fixing, etc.

TDD slows you down because when you want to change how something behaves to implement a new feature, you will probably break existing tests and need to fix them.  This is where my "shoot yourself in the foot" comment stems from.  The first major set of code I attempted to use TDD style was actually a retrofit of code without any unit tests.  So my "unit" tests actually test FAR too much per test.  I change one thing and I break 50 tests.  This is bad!  This is not how TDD should work!  Tests should not overlap, so the fewest number of tests should fail per change you make, so you can either figure out if you introduced a bug, or you forgot to update the test to reflect the new behavior.

TDD DRAMATICALLY helps you get code right the first time and reduces time wasted manually testing (i.e. paying a QA team to waste their time testing stuff you can test automatically with no human salary involved).  Really good programmers can often get code right the first time without TDD, but I have had people break my code countless times so I'm learning that it doesn't matter how good I am at programming if I'm not the only person on the team.  I'm hoping that I can introduce TDD at work to prevent code from being eroded over time.

(In My Opinion) Retrofitting unit tests into code that you wrote before TDD is what causes cumbersome interfaces, which led to the development of dependency injection frameworks.  If you start with TDD you should be able to avoid writing code with interfaces that are too complex to test using simple tests and too complex to initialize easily.  I may change my mind about dependency injection frameworks later after I use TDD more but for now I don't like them because they feel like one giant code smell to me.

Edited by Nypyren

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
  • Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Armaan Gupta
      Hey There,
      I am a developer and Im working on a blockchain based infinite runner type game. Right now, I am working on releasing the beta version with a couple other game developers, but would love to expand the team and have other talented and bright people contributing. The game portion of the project isnt very complicated, and wouldnt require anyone to pull thier hair out for it.
      If you are interested in joining a project, interested in the idea, or would like some more information, please don't hesitate to ask either by commenting, discord (username: Guppy#7625), or by email (armaangupta01@gmail.com).
      Thank you!
    • By Joydeep Mani
      I am trying to build a particle system for unity based on "Destiny particle architecture " released in Siggraph.
      I encounter a problem in trying to understand how they iterated this:

      Converted to spline function and the result is

      i wanted to know how did they converted the function in the editor to represent the graph ??
       
    • By Xerath Dragons
      This is my first experiment use for create my original character little cute dragon chibi use zbrush and blender and use unity3d assest free for enviroment scene you have feedback?
       


    • By Aryndon
      Project Redemption is an semi-fantasy RPG with a linear story and an elaborate combat system.
      We are building in Unity and are currently looking animators and artists.
      What we are looking for
      -Someone who is okay with split revenue/profits when finished
      -Collaborate with others in the team. Do you have an idea/thought on what should be included? Tell us!
      -Someone who wants to work with people that are passionate about this project
      If you are interested. Please message me and I will get back to you as soon as possible! Or add me on Discord AJ#6664
    • By Aggrojag
      Hello!
      I'm working on a game that is a narrative driven dark comedy with some small aspects of platforming and puzzle solving. The project is rather small as well. It touches on topics such as suicide, mental illness, family, corruption, free-will, and redemption.
      This project is exercise in polish, this means some experimentation will be needed along with some reworking of assets as they're provided.
      This will be a revshare model.
      First, I'm looking for a 2D sprite artist, not pixelated, that can compliment the style of the attached images, and be similar to the temporary character.
      We are looking to bring on a SFX designer at this time. Full list of required SFX will be available upon request, as well as a build with all elements related to sound implemented in some form (many SFXs pulled from the web for now). Will likely require some field recording, and some pretty strange SFX for when things get weird. I imagine a good portion of these will be quite fun to create.
      Lastly, I'm looking for a male voice actor, English should be your primary language. There will be at minimum two characters that will need to be brought to life through vocals. The first voice is similar to Marvin from Hitchhiker's Guide to the Galaxy. A reference for the second voice would be a mix of Ren (Ren & Stimpy), and Android 21 (DragonBallFighterZ). Due to formatting, I'm not including YouTube links in the post, sorry.
       
      WIP Scene with our custom shaders attached (platforms are lazily placed, as this was an asset test):

      A scene with dynamic lighting and temp character:

       
      Unshaded asset:

      If you made it to the bottom, thank you, and I look forward to hearing from you.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!