Answers.Body: <p>The most fundamental shift in my programing came from my attitude about details.</p>
  <p>When I was young I wanted to pull every detail out of everything I touched, pin in down in front of me in one source file and beat it into submission. I could stand in one place and know everything.</p>
  <p>After decades of programming my attitude is: the less I know the better. Dealing with a detail? Feh, I let other things deal with that. I already have plenty of stuff to think about right here thank you. I don't need more clutter.</p>
  <p>I have shifted from a procedural mind set to a more abstract one.</p>
  <p>That sounds fancy but all it means is that no mater where I am in the code, I want to think about only one problem, in only one way, from only one perspective.  Any detail that distracts from that is getting tucked away somewhere. I work very hard to make it that easy because I'm that lazy.</p>
  <p>There are many ways to try to teach this, problems that invite students to drown themselves in details if they aren't careful. But one guiding principle has helped me see when I'm doing it right.  It has many names but the one I'm most fond of is:</p>
  <h1>Tell. Don't ask.<sup><a href="https://pragprog.com/articles/tell-dont-ask" rel="nofollow noreferrer">1</a>,<a href="https://martinfowler.com/bliki/TellDontAsk.html" rel="nofollow noreferrer">2</a>,<a href="https://robots.thoughtbot.com/tell-dont-ask" rel="nofollow noreferrer">3</a>,<a href="http://deviq.com/tell-dont-ask/" rel="nofollow noreferrer">4</a>,<a href="http://tmichel.github.io/2015/09/14/oo-controversies-tell-dont-ask-vs-the-web/" rel="nofollow noreferrer">5</a></sup></h1>
  <p>If I have to ask a question then I have to deal with the answer. Usually that's a detail. The only reason I ask is because I want to do something and I don't have enough information to do it. Why can't I just tell the thing I asked to just do my something? It knows the answer, so it knows what it needs already. I should be able to just tell it &quot;do it now&quot; and it should be able to go do it without making me think about it.</p>
  <p>Adopt this attitude and working abstractly becomes very appealing. Without it, abstraction and polymorphism are very annoying because they're getting in the way of you knowing everything. Teach your students to love not knowing.</p>
  <p>I don't know. I don't want to know.</p>
  <hr />
  <p>How to motivate students to use this?</p>
  <p>Don't.</p>
  <p>Motivate them to explore it. Which is better is not a settled issue. What you should teach is what problems this style addresses. How to identify situations that create a greater need for it. How to identify situations where it's irrelevant.</p>
  <p>I've been studying every programming principle and style I could find for decades now and not one of them is something I would advise someone to adopt without critically analyzing how and whether to apply it in any given situation.</p>
  <p>What I do recommend is practicing with them. Until you've used one while solving a real problem all your doing is being a tourist. I've watched people end their career by waving a book around preaching principles without knowing how to solve a problem.</p>
  <p>When interviewing prospects I'd rather hear:</p>
  <p>&quot;If you follow principle x it may help with this y issue.&quot;</p>
  <p>than</p>
  <p>&quot;You should always follow principle x. It's good design. Professionals always follow good design.&quot;</p>
  <p>Spare me from fanatics that follow rules without thinking.</p>
  <p>Encourage them to learn every principle, pattern, and practice they can. Not because they should always use them, but because when they look at code that already uses them they should understand why the code looks the way it does.</p>
  <p>The reality is true professionals spend most of their time wading through crap code trying to get what they need out of it while causing the smallest amount of fuss they can.</p>
  <p>The really good ones will spot some tiny little improvement they might be able to get away with while they're here. These &quot;boy scouts&quot; leave the code a little better than they found it. Give me those over the crusaders that want a complete rewrite every time they look at a new code base.</p>
  <p>Cultivate in them a skeptical &quot;boy scout&quot; attitude. Give them all the tools but teach them to use them sparingly, wisely, and carefully.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-07T16:43:21.963Z
Answers.Text: I see what you're saying. However the problem remains: I am asking how can I *motivate* the students to try and make their code more abstract.
  
  Don't get me wrong, I'll definitely use "Tell. Don't ask." . But that's not exactly the problem.
Answers.UserDisplayName: ItamarG3
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-08T06:05:23.540Z
Answers.Text: @ItamarG3 better?
Answers.UserDisplayName: candied_orange
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-08T06:07:46.147Z
Answers.Text: Yes. The answer in itself is better, though I personally don't quite agree. But it definitely is better. Thanks :P. A point to note is, again, I am not their **teacher**, I am a mentor. I don't teach them, I guide them while they do independent work.
Answers.UserDisplayName: ItamarG3
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-08T06:16:40.510Z
Answers.Text: @ItamarG3 I've been on teams where I was just another coder, had no authority other than being known as a good guy to ask questions, and I still found myself "teaching". If you have a similar ability to influence them please take it just as seriously as a teacher would. This field is less than 100 years old. We're all still learning. Please help where you can. Your menties may just write code that drives my car some day.
Answers.UserDisplayName: candied_orange
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-07T12:07:03.877Z
Answers.LastActivityDate: 2018-02-22T09:31:44.313Z
Answers.LastEditDate: 2020-06-18T08:36:57.023Z
Answers.UserDisplayName: candied_orange
Answers.Body: <p>Based on my past experience working on a FRC team, my main advice would be to be very cautious about pushing students to use more advanced abstractions, design patterns, and whatnot.</p>
  
  <p>The issue is that if you spend a lot of up-front effort designing interfaces and abstraction layers, you can end up painting yourself into a corner, especially if you're new to programming and don't have a good sense of how to anticipate these sorts of things.</p>
  
  <p>For example, take the forklift example you mentioned -- what happens if the students decide half-way through the design season that they don't want to use the forklift design after all, and want to create some sort of arm? Or what if they want to create some kind of kicker thing to try punt a ball of some sort?</p>
  
  <p>Or even with the forklift example -- what if the team switches from using some sort of conveyor-belt design (where the user can control the height of the lift) to some sort of pneumatic based system, where the height ends up being basically binary (low or high)? How do you design an interface that can accommodate both (without stuffing the interface full of different methods that are inconsistently implemented across different subclasses)?</p>
  
  <p>And for all of these, how do you map of these to the user interface, which again the team might want to wildly change over time?</p>
  
  <p>None of these issues are insurmountable of course -- you can work around it by having a clever and flexible set of abstractions, or by having a more solid design phase (and pruning down deviations from the initial plan).</p>
  
  <p>That said, no plan is perfect and the danger is that too-brittle and overly restrictive abstractions can potentially end up crippling the team down the line.</p>
  
  <p>This means you should be careful when pushing for more abstraction -- the danger is that if the abstractions you propose end up hampering the team down the line, they might end up resenting the idea of them and take away entirely the wrong lesson: abstractions are bad, and are not worth the trouble.</p>
  
  <hr>
  
  <p>So, for that reason, I recommend taking a more "organic" approach. Let students write code, and push them to write it in the simplest way possible. The code initially is probably going to be messy, but that's fine -- if your FRC team is anything like mine, there's probably a fair bit of prototyping in the first week or two (or even up to the last week...).</p>
  
  <p>As you see redundancy, point it out, and push students to <em>refactor</em> it. Try and emphasize this sort of procedural refactoring first.</p>
  
  <p>Next, encourage students to create <em>objects</em> to encapsulate behavior and state. Somebody introduces a new subsystem? Create an object for it. Somebody wants to play with a new UI? Another object. Don't worry about having these objects conform to any kind of interface/extend any object -- getting them to think about subsystems as distinct units/distinct objects would be a good step.</p>
  
  <p>Finally, near the endgame, as the design as settled and people are iterating, start introducing the idea of interfaces. The overall design of your subsystems are probably fixed at this point, and the team is likely focused on iterating. In that case, you can probably now create an interface per each subsystem and create a new subclass per each distinct variation or something.</p>
  
  <p>That way, if the team wants to trial-run one particular variation, it's easy to swap out the corresponding code.</p>
  
  <p>You can maybe facilitate this whole process by having code reviews, perhaps on a weekly basis or something. This lets students still retain ownership of the code while still giving you a mechanism to propose changes or give advice.</p>
  
  <p>This does mean, however, that your advice will (at least initially) be reactive, rather then proactive. However, I don't think that's necessarily a bad thing -- it's good for the students to have ownership of their code, make mistakes, learn from them, etc...</p>
  
  <p>And if the team never really does get to the point where using interfaces and such makes sense, don't bother bringing it up. Realistically, the code they're writing is likely going to be simple, in the grand scheme of things. Don't over-complicate it.</p>
  
  <p><strong>Edit:</strong> A little more specifically, I'm fond of the "rule of three" (<a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)" rel="nofollow noreferrer">link 1</a>, <a href="https://blog.codinghorror.com/rule-of-three/" rel="nofollow noreferrer">link 2</a>). </p>
  
  <p>I would try and drill in this principle into your students: when you see something repeated three or more times, that's a good point to think about refactoring and abstracting. Basically, my opinion is that the hard part is learning <em>when</em> it's appropriate to refactor or abstract. If you can teach them to identify when to abstract, it's comparatively easier to teach them <em>how</em>.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-07T19:33:02.400Z
Answers.LastActivityDate: 2018-02-08T21:40:01.947Z
Answers.LastEditDate: 2018-02-08T21:40:01.947Z
Answers.UserDisplayName: Michael0x2a
Answers.Body: <p>Perhaps it would help them to see the difference between their current code and some better code. Better code might also make their future work on this project easier. The trick is to get them to create the better code themselves without it seeming like they are throwing things away. </p>
  
  <p>There are two skills that you can teach them that you can promise will be useful to them if they carry on in CS. Testing and Refactoring. </p>
  
  <p>When code does what it should but is not as maintainable as it should be, or not as easy to extend, or just ugly, you want to <strong>Refactor</strong> it. Change its structure without changing its behavior. This is one of the core skills in Agile Software Development. </p>
  
  <p>The problem with actually doing that, however, is to know that when you make a change to the code you haven't changed its actual behavior. So, you need to <strong>Test</strong> it. But you want those tests anyway so that you have confidence that when you extend (i.e. not refactoring) that you don't break things you wrote earlier. </p>
  
  <p>So, assuming Java, use something like <a href="https://junit.org/junit5/" rel="nofollow noreferrer">JUnit</a> to create "unit tests" that test the behavior of the public methods of the code. Be sure to test both the main cases and the "edge" cases. These tests capture the <em>semantics</em> of the code, in fact. Ultimately the real-meaning of the code is what it does. Hopefully that matches the intended meaning. Tests can tell you this. </p>
  
  <p>Then, tests in hand and all passing, you can change the code freely. As long as the tests continue to pass you haven't changed the behavior. There are lots of possible refactoring, such as the ones suggested in the above question, but others as well. Simplifying methods by factoring out private helpers. Creating private classes so that you can create helper objects so that each piece of code becomes simpler, etc. </p>
  
  <p>You, as a teacher (or helper) can even make it a game giving prizes for the most effective refactoring, or the most successfully passing tests. </p>
  
  <hr>
  
  <p>As a pedagogical technique that may be acceptable to the actual instructor in your situation is that you can pair with a student (or triple with a pair) and create some of the tests yourself. I say this may be acceptable, since you aren't providing functionality to their work, but only the framework in which they can extend it. Your example can give them the hang of how to go about it. </p>
  
  <hr>
  
  <p>This same technique is used in situations in which you have to deal with some old code written by others (a "dusty deck") and don't understand it yourself. Write tests to capture what you think it is doing. If the tests pass then it really is doing that. Once you have understanding you can either refactor or extend, knowing that you didn't break anything. </p>
  
  <hr>
  
  <p>The effect of this technique should result in the goals suggested in the answer of <a href="https://cseducators.stackexchange.com/a/4306/1293">CandiedOrange</a> here. </p>
  
  <hr>
  
  <p>Ideally, tests are written along with the code, actually before the code. If the tests already exist and were written to drive the development itself, then the refactoring step is easier. The mantra for developing code from the start is <em>No Code Without A Failing Test</em>. This is called <em>Test Driven Development</em>. It is a fun skill in itself. Write a test that must fail since it has no code to back it up. Let the test capture the intended meaning. Then write just enough application code to make the test pass. Repeat until done. </p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-07T12:50:21.913Z
Answers.LastActivityDate: 2018-02-07T18:59:19.920Z
Answers.LastEditDate: 2018-02-07T18:59:19.920Z
Answers.UserDisplayName: Buffy
Body: <p>I mentor an <a href="https://www.firstinspires.org/robotics/frc" rel="nofollow noreferrer">FRC (<em>FIRST</em> Robotics Competition)</a> team, and they program in java.</p>
  
  <p>The team members who work programming the robot are using an extension<sup>1</sup> library which they themselves write.</p>
  
  <p>The library that they write doesn't exactly follow good design concepts. for example, instead of having an interface for describing the functionality of a moving subsystem (a robotic forklift, for instance), they have a class that extends a subsystem, and it contains that functionality.</p>
  
  <p>This is one example, and there are quite a few other examples. I say this to explain that they have quite a bit of code already written, and it would be difficult to make it more abstract and write it with a higher level of design.</p>
  
  <p>So my question is <em>how can I approach the subject, and encourage the students to want to learn and use higher levels of abstractions</em>?</p>
  
  <p>By "approach", I mean bring up the matter, without making it sound as though I think they <strong>have</strong> to do it, or that their code "won't ever be good unless they do it".</p>
  
  <p>The students <em>can</em> learn it (i.e. they are able and capable of learning those concepts). This question isn't about how to <em>teach</em> it, but rather how to <em>encourage the students</em> to want to learn and apply those concepts</p>
  
  <p>A clarification: I am not their teacher, I am a mentor. I do not <strong>teach</strong> them, but rather I help them learn (it's informal)</p>
  
  <p>Proper design and abstraction makes code, especially libraries, easier to maintain and easier to use, and also prevents some types of bugs and errors.<br>
  That is one of the main points of design patterns, as well as a "side-effect" of following SOLID principles.</p>
  
  <hr>
  
  <p><sup>1</sup>Without going into too much details, I'll say that there is a <a href="https://github.com/wpilibsuite/allwpilib" rel="nofollow noreferrer">supplied library</a> for programming the robot, and the team is writing an extension of that library. </p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-02-07T09:35:09.050Z
Comments.Text: Provide the interface, and have them implement it (May be in breach of competition rules, may not work with the existing system).
Comments.UserDisplayName: ctrl-alt-delor
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-02-07T09:37:22.820Z
Comments.Text: What value is it to them? How will it make the program better? (Don't tell be it is a rule; That is what good programs look like; Show me why it makes the program better.)
Comments.UserDisplayName: ctrl-alt-delor
Tags: <student-motivation><object-oriented-paradigm><abstraction>
Title: Encourage students to learn and use advanced design
ThreadText: # Encourage students to learn and use advanced design
  
  (Asked by: username_0 on 2018-02-07)
  
  I mentor an [FRC (*FIRST* Robotics Competition)](https://www.firstinspires.org/robotics/frc) team, and they program in java.
  
  The team members who work programming the robot are using an extension1 library which they themselves write.
  
  The library that they write doesn't exactly follow good design concepts. for example, instead of having an interface for describing the functionality of a moving subsystem (a robotic forklift, for instance), they have a class that extends a subsystem, and it contains that functionality.
  
  This is one example, and there are quite a few other examples. I say this to explain that they have quite a bit of code already written, and it would be difficult to make it more abstract and write it with a higher level of design.
  
  So my question is *how can I approach the subject, and encourage the students to want to learn and use higher levels of abstractions*?
  
  By "approach", I mean bring up the matter, without making it sound as though I think they **have** to do it, or that their code "won't ever be good unless they do it".
  
  The students *can* learn it (i.e. they are able and capable of learning those concepts). This question isn't about how to *teach* it, but rather how to *encourage the students* to want to learn and apply those concepts
  
  A clarification: I am not their teacher, I am a mentor. I do not **teach** them, but rather I help them learn (it's informal)
  
  Proper design and abstraction makes code, especially libraries, easier to maintain and easier to use, and also prevents some types of bugs and errors.  
  That is one of the main points of design patterns, as well as a "side-effect" of following SOLID principles.
  
  ---
  
  1Without going into too much details, I'll say that there is a [supplied library](https://github.com/wpilibsuite/allwpilib) for programming the robot, and the team is writing an extension of that library.
  
  **Tags:** student-motivation, object-oriented-paradigm, abstraction
  
  > **Comments:**
  > **username_1**: Provide the interface, and have them implement it (May be in breach of competition rules, may not work with the existing system).  
  > **username_1**: What value is it to them? How will it make the program better? (Don't tell be it is a rule; That is what good programs look like; Show me why it makes the program better.)  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_2 on 2018-02-07. Score: 4 | Accepted answer
  
  The most fundamental shift in my programing came from my attitude about details.
  
  When I was young I wanted to pull every detail out of everything I touched, pin in down in front of me in one source file and beat it into submission. I could stand in one place and know everything.
  
  After decades of programming my attitude is: the less I know the better. Dealing with a detail? Feh, I let other things deal with that. I already have plenty of stuff to think about right here thank you. I don't need more clutter.
  
  I have shifted from a procedural mind set to a more abstract one.
  
  That sounds fancy but all it means is that no mater where I am in the code, I want to think about only one problem, in only one way, from only one perspective. Any detail that distracts from that is getting tucked away somewhere. I work very hard to make it that easy because I'm that lazy.
  
  There are many ways to try to teach this, problems that invite students to drown themselves in details if they aren't careful. But one guiding principle has helped me see when I'm doing it right. It has many names but the one I'm most fond of is:
  
  # Tell. Don't ask.[1](https://pragprog.com/articles/tell-dont-ask),[2](https://martinfowler.com/bliki/TellDontAsk.html),[3](https://robots.thoughtbot.com/tell-dont-ask),[4](http://deviq.com/tell-dont-ask/),[5](http://tmichel.github.io/2015/09/14/oo-controversies-tell-dont-ask-vs-the-web/)
  
  If I have to ask a question then I have to deal with the answer. Usually that's a detail. The only reason I ask is because I want to do something and I don't have enough information to do it. Why can't I just tell the thing I asked to just do my something? It knows the answer, so it knows what it needs already. I should be able to just tell it "do it now" and it should be able to go do it without making me think about it.
  
  Adopt this attitude and working abstractly becomes very appealing. Without it, abstraction and polymorphism are very annoying because they're getting in the way of you knowing everything. Teach your students to love not knowing.
  
  I don't know. I don't want to know.
  
  ---
  
  How to motivate students to use this?
  
  Don't.
  
  Motivate them to explore it. Which is better is not a settled issue. What you should teach is what problems this style addresses. How to identify situations that create a greater need for it. How to identify situations where it's irrelevant.
  
  I've been studying every programming principle and style I could find for decades now and not one of them is something I would advise someone to adopt without critically analyzing how and whether to apply it in any given situation.
  
  What I do recommend is practicing with them. Until you've used one while solving a real problem all your doing is being a tourist. I've watched people end their career by waving a book around preaching principles without knowing how to solve a problem.
  
  When interviewing prospects I'd rather hear:
  
  "If you follow principle x it may help with this y issue."
  
  than
  
  "You should always follow principle x. It's good design. Professionals always follow good design."
  
  Spare me from fanatics that follow rules without thinking.
  
  Encourage them to learn every principle, pattern, and practice they can. Not because they should always use them, but because when they look at code that already uses them they should understand why the code looks the way it does.
  
  The reality is true professionals spend most of their time wading through crap code trying to get what they need out of it while causing the smallest amount of fuss they can.
  
  The really good ones will spot some tiny little improvement they might be able to get away with while they're here. These "boy scouts" leave the code a little better than they found it. Give me those over the crusaders that want a complete rewrite every time they look at a new code base.
  
  Cultivate in them a skeptical "boy scout" attitude. Give them all the tools but teach them to use them sparingly, wisely, and carefully.
  
  > **Comments:**
  > **username_0**: I see what you're saying. However the problem remains: I am asking how can I *motivate* the students to try and make their code more abstract.  Don't get me wrong, I'll definitely use "Tell. Don't ask." . But that's not exactly the problem.  
  > **username_2**: @username_0 better?  
  > **username_0**: Yes. The answer in itself is better, though I personally don't quite agree. But it definitely is better. Thanks :P. A point to note is, again, I am not their **teacher**, I am a mentor. I don't teach them, I guide them while they do independent work.  
  > **username_2**: @username_0 I've been on teams where I was just another coder, had no authority other than being known as a good guy to ask questions, and I still found myself "teaching". If you have a similar ability to influence them please take it just as seriously as a teacher would. This field is less than 100 years old. We're all still learning. Please help where you can. Your menties may just write code that drives my car some day.  
  
  ---
  
  ### Answer by username_3 on 2018-02-07. Score: 2
  
  Based on my past experience working on a FRC team, my main advice would be to be very cautious about pushing students to use more advanced abstractions, design patterns, and whatnot.
  
  The issue is that if you spend a lot of up-front effort designing interfaces and abstraction layers, you can end up painting yourself into a corner, especially if you're new to programming and don't have a good sense of how to anticipate these sorts of things.
  
  For example, take the forklift example you mentioned -- what happens if the students decide half-way through the design season that they don't want to use the forklift design after all, and want to create some sort of arm? Or what if they want to create some kind of kicker thing to try punt a ball of some sort?
  
  Or even with the forklift example -- what if the team switches from using some sort of conveyor-belt design (where the user can control the height of the lift) to some sort of pneumatic based system, where the height ends up being basically binary (low or high)? How do you design an interface that can accommodate both (without stuffing the interface full of different methods that are inconsistently implemented across different subclasses)?
  
  And for all of these, how do you map of these to the user interface, which again the team might want to wildly change over time?
  
  None of these issues are insurmountable of course -- you can work around it by having a clever and flexible set of abstractions, or by having a more solid design phase (and pruning down deviations from the initial plan).
  
  That said, no plan is perfect and the danger is that too-brittle and overly restrictive abstractions can potentially end up crippling the team down the line.
  
  This means you should be careful when pushing for more abstraction -- the danger is that if the abstractions you propose end up hampering the team down the line, they might end up resenting the idea of them and take away entirely the wrong lesson: abstractions are bad, and are not worth the trouble.
  
  ---
  
  So, for that reason, I recommend taking a more "organic" approach. Let students write code, and push them to write it in the simplest way possible. The code initially is probably going to be messy, but that's fine -- if your FRC team is anything like mine, there's probably a fair bit of prototyping in the first week or two (or even up to the last week...).
  
  As you see redundancy, point it out, and push students to *refactor* it. Try and emphasize this sort of procedural refactoring first.
  
  Next, encourage students to create *objects* to encapsulate behavior and state. Somebody introduces a new subsystem? Create an object for it. Somebody wants to play with a new UI? Another object. Don't worry about having these objects conform to any kind of interface/extend any object -- getting them to think about subsystems as distinct units/distinct objects would be a good step.
  
  Finally, near the endgame, as the design as settled and people are iterating, start introducing the idea of interfaces. The overall design of your subsystems are probably fixed at this point, and the team is likely focused on iterating. In that case, you can probably now create an interface per each subsystem and create a new subclass per each distinct variation or something.
  
  That way, if the team wants to trial-run one particular variation, it's easy to swap out the corresponding code.
  
  You can maybe facilitate this whole process by having code reviews, perhaps on a weekly basis or something. This lets students still retain ownership of the code while still giving you a mechanism to propose changes or give advice.
  
  This does mean, however, that your advice will (at least initially) be reactive, rather then proactive. However, I don't think that's necessarily a bad thing -- it's good for the students to have ownership of their code, make mistakes, learn from them, etc...
  
  And if the team never really does get to the point where using interfaces and such makes sense, don't bother bringing it up. Realistically, the code they're writing is likely going to be simple, in the grand scheme of things. Don't over-complicate it.
  
  **Edit:** A little more specifically, I'm fond of the "rule of three" ([link 1](https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)), [link 2](https://blog.codinghorror.com/rule-of-three/)).
  
  I would try and drill in this principle into your students: when you see something repeated three or more times, that's a good point to think about refactoring and abstracting. Basically, my opinion is that the hard part is learning *when* it's appropriate to refactor or abstract. If you can teach them to identify when to abstract, it's comparatively easier to teach them *how*.
  
  
  ---
  
  ### Answer by username_4 on 2018-02-07. Score: 0
  
  Perhaps it would help them to see the difference between their current code and some better code. Better code might also make their future work on this project easier. The trick is to get them to create the better code themselves without it seeming like they are throwing things away.
  
  There are two skills that you can teach them that you can promise will be useful to them if they carry on in CS. Testing and Refactoring.
  
  When code does what it should but is not as maintainable as it should be, or not as easy to extend, or just ugly, you want to **Refactor** it. Change its structure without changing its behavior. This is one of the core skills in Agile Software Development.
  
  The problem with actually doing that, however, is to know that when you make a change to the code you haven't changed its actual behavior. So, you need to **Test** it. But you want those tests anyway so that you have confidence that when you extend (i.e. not refactoring) that you don't break things you wrote earlier.
  
  So, assuming Java, use something like [JUnit](https://junit.org/junit5/) to create "unit tests" that test the behavior of the public methods of the code. Be sure to test both the main cases and the "edge" cases. These tests capture the *semantics* of the code, in fact. Ultimately the real-meaning of the code is what it does. Hopefully that matches the intended meaning. Tests can tell you this.
  
  Then, tests in hand and all passing, you can change the code freely. As long as the tests continue to pass you haven't changed the behavior. There are lots of possible refactoring, such as the ones suggested in the above question, but others as well. Simplifying methods by factoring out private helpers. Creating private classes so that you can create helper objects so that each piece of code becomes simpler, etc.
  
  You, as a teacher (or helper) can even make it a game giving prizes for the most effective refactoring, or the most successfully passing tests.
  
  ---
  
  As a pedagogical technique that may be acceptable to the actual instructor in your situation is that you can pair with a student (or triple with a pair) and create some of the tests yourself. I say this may be acceptable, since you aren't providing functionality to their work, but only the framework in which they can extend it. Your example can give them the hang of how to go about it.
  
  ---
  
  This same technique is used in situations in which you have to deal with some old code written by others (a "dusty deck") and don't understand it yourself. Write tests to capture what you think it is doing. If the tests pass then it really is doing that. Once you have understanding you can either refactor or extend, knowing that you didn't break anything.
  
  ---
  
  The effect of this technique should result in the goals suggested in the answer of [username_2](https://cseducators.stackexchange.com/a/4306/1293) here.
  
  ---
  
  Ideally, tests are written along with the code, actually before the code. If the tests already exist and were written to drive the development itself, then the refactoring step is easier. The mantra for developing code from the start is *No Code Without A Failing Test*. This is called *Test Driven Development*. It is a fun skill in itself. Write a test that must fail since it has no code to back it up. Let the test capture the intended meaning. Then write just enough application code to make the test pass. Repeat until done.
  
  
  ---
  
  