With large pieces of software, it's not really an RTOS specific question, but more a general question, and best answered by CompSci people
(hopefully there are some on the forum).
There are recommended practices to developing complex software, but usually a framework and architecture is employed.
(For example, if you were running on Linux, then ACE (**broken link removed**) could be used. It provides a library of
functions that support real-time software). Here is an example of what I mean: Say you wanted to pass information from one process to another.
You could use the (effectively) low-level features found in the RTOS, such as mutexes. However, if you have a framework and supporting
software, then it will provide the functions to pass information without needing to use the low-level features, and you'd be able to
wait and act on the information in a more scalable and easier way for larger software, e.g. pass any type of variable type, arrays etc,
and invoke a process just to handle the data, and and it would probably log and provide debug information too, so that you can troubleshoot
your larger code easier.
When you're talking about a microcontroller, then the chances are that the code, while large, is probably still small enough that you
may not need such sophisticated features, but nevertheless it's a decision you need to make - should you spend time creating functions
that will provide supporting features for your main software, like good logging functions, debugging functions etc? Probably yes.
Programming language is also important. There are people who will suggest "you can do anything in C" or "you can do anything in assembler"
but if you've got the space, then C++ will make your life simpler.
Also, there are some well-established methods for doing certain common things. As you've spotted, a state machine is an established method.
Similarly, there are established ways to handle data structures, and established ways to do a whole host of "things". You'd probably need
to spend a few days reading up a book on design patterns. So much to read..
If you're coding for a uni project, then you won't have time to do everything listed above. But then again, you possibly don't need to -
it is possible to implement a lot of software even without an RTOS for example, or using very few processes and try to keep it as simple
as possible - the more processes and complexity then the more troubleshooting that is needed when you get conditions that
were unexpected because of process execution speeds and synchronization, and then the more the need for better logging and
debugging features..
In short, spend some time figuring out what bits of code need to share data or synchronize, can you collapse to a few processes,
and do you have some good debugging facilities.