Most of our students use RStudio for their work. It's convenient and easy. For developing standalone scripts or functions, rather than notebooks or R Markdown files, the typical workflow is to write code in a file, then run it in the current R session by selecting pieces and hitting "Run".
But this encourages terrible practices. After a few iterations, the current environment does not reflect what's written in the file. If students write tests in a separate file, they neglect to source in their functions, because they're already in the workspace and so the tests run fine. Datasets that were loaded in the R console are used in code without being explicitly loaded there. Code gets changed without being run, or variable definitions are changed but old copies in the workspace accidentally used instead.
We end up getting many homework submissions that simply don't run if you start them in a new R session. Pieces are missing, code is out of order, tests only run if you manually select the test code and run it. It only worked in the R session of the original author.
R Markdown is a decent step, since rendering the HTML should start a session from scratch, but when we're asking them to write well-tested and modular algorithmic code, using R Markdown doesn't really fit.
I've begun to appreciate DrRacket's approach, where there is a "Definitions" pane and an "Interactions" window. When you Run the definitions, the current workspace is blown away and everything is defined from scratch from the Definitions, so there's no lingering state from REPL interactions. (Unfortunately your REPL history is lost, which can be annoying.) You can't run into the same inconsistent state as RStudio actively encourages.