Learning is by definition a "stressful" experience, in that obtaining new knowledge stresses the brain. However, there's a difference between eustress ("good stress", e.g. doing a Sudoku puzzle) and distress ("bad stress", e.g., being yelled at by your boss). Constant bad stress especially decreases your ability to learn, but is actually beneficial in small doses. See this Nature article for a good overview: https://www.nature.com/articles/npjscilearn201611 There have also been studies that taking mini-breaks from stress when learning help improve retention: https://www.ninds.nih.gov/News-Events/News-and-Press-Releases/Press-Releases/Want-learn-new-skill-Take-some-short-breaks
I try not to make my lectures or explanations too dense, and make random digressions to provide a "mental break". For instance, in my software engineering classes, when I discuss how sometimes the best code is no code, I'll do a quick talk about Arthur Schopenhauer's philosophy of antinatalism ("the worst thing that can happen to you is to to exist"). I'll joke, I'll use funny examples or method names, etc. I try to keep it light instead of serious when LEARNING, and more serious instead of light when they are IMPLEMENTING. This provides a good "no-stress/eustress cycle" which seems optimal for students to understand concepts.
The human mind is great at picking up on examples and extrapolating. It is worse at understanding things from first principles. I always try to make sure I have lots of example code for any topic. For example, when teaching mocking, I have different examples of using different kinds of test doubles (dummies, doubles w/ stubs, mocks, etc.) and why they are useful. https://github.com/laboon/CS1632_Spring2019/blob/master/sample_code/mock_example/graph_test.rb
Similarly, I try to make real-world projects as opposed to abstract "implement a linked list"-style projects. For example, the final deliverable for my QA class was verifying a blockchain: https://github.com/laboon/CS1632_Spring2019/blob/master/deliverables/4/billcoin.md. I try to do this even for very simple things. For example, I'm proud of the labs I did when I taught an "Intro to Java" class. Instead of just teaching array re-sizing, I had students implement different gardens for the optimistic Professor Pangloss and the pessimistic Martin (from Voltaire's Candide) - https://github.com/laboon/cs0401/blob/master/labs/lab08/Lab08.md - or taught people about utilitarianism along with switch statements - https://github.com/laboon/cs0401/blob/master/labs/lab04/lab04.md
There should always be a way forward in learning, especially at the start of learning a new skill. There is of course value to working hard on a particular question, and sometimes students will just stare at an empty screen. When introduced to a new topic, students often don't have the foundational knowledge to know how to try different things - it's Donald Rumsfeld's idea of an "unknown unknown".
When students are not forced to learn something (e.g. online workshops), this is especially important. Drop-out rates of online courses are already sky-high; something as simple as a typo in a command may cause a student to give up. We can learn a lot from Duolingo in this regard - one of the things we learned when I worked at Think Through Math was that by far the most significant indicator of how much someone would improve at math was simply how much time did they spend doing math problems. Of course, there are smaller efficiencies to be had in improving questions, ordering, etc. but the key take-away is to make sure students keep making forward progress, and they will keep working on things, and thus will gain knowledge.
This means that there should be lots of troubleshooting, an open and welcoming environment to ask questions, and very detailed and well-tested instructions. For example, I really try to make sure students know "there are no dumb questions - if you get stuck, come talk to me". This is not really scalable for an individual that's (~ O(n)), and hard to have everything written out in the wiki (~ O(1)) but by ensuring we have a welcoming community who help out others, it can be close to ~ O(log n).
Students tend learn Topic A first, then Topic B, etc. In programming, however, it is rare that you have to do only one topic at a time. Rather, you need to make sure that topics build on each other. I introduce systems-level testing, unit testing, static analysis, etc. but by the end of the term students are working on projects which involve all of these things, and determining when it is best to use them.
Early on, it's hard to avoid making everything discrete topics, but I try to move relatively quickly to "mixing" topics.
Very good text! I would like to read something more from you!