26
$\begingroup$

I have a background of 20+ years professional coding, but my heart is really in teaching. About three years ago, I started tutoring ages grade 6 through adult in coding topics.

  • introduction to coding in Python or Java
  • AP CS A help
  • for independent students, long-term projects like an role-playing game
  • competitions (CodeWars, US Computing Olypiad)

I like my code to be simple and comprehensible, with the feeling of confidence that it works... a simple thought process by which I can understand (and anyone can understand) what my code does.

So I teach that. I teach breaking things into encapsulated sections, I teach testing and debugging techniques.

I also teach how to make use of your brain better and work smart, not hard.

Several of my students have been with me for three years, and they've all grown a lot, and they're a pleasure to work with because they picked up this clean thought style.

But... is this the only approach to teaching? Is it the best approach?

Keep in mind that most of my students aren't going to be professional coders. Keep in mind that I'm a bit obsessive and probably could stand to lighten up a little and let my students work in whatever way they would like.

Recently a student came to me, interested in doing US Computing Olympiad problems. The thing is, he had barely learned anything about coding. He had a little Java knowledge, but was weak on creating classes and really didn't even understand how to use functions. I suggested that we work on fundamentals and he balked - from his point of view, you didn't need functions to solve these problems, and he had searched the web for other solutions and none of them used functions. (All the code is in main())

At first I figured he was in for a disappointment when he realized these problems were over his head. Well, shiver me timbers, he has solved about 10 problems so far using this technique. I can't even figure out what his code is doing or why it should work.

He doesn't do testing even! He just submits his code and keeps tweaking it until it passes the online judge test cases.

So I finally said that consider it a limitation on my part, I'm only really able to work in my normal method and that if he really doesn't want to do things my way, he has to find a tutor who can work with him like this.

Finally there came a reason why he's interested in me and my methods - he did see that it would be useful to test and debug, and he did find a few USACO solution online that used functions and classes, so now he has a mild interest in learning that from me.

I guess what I'm asking then, is when you are mentoring someone, how do you negotiate this balance between "teaching them clean work" and "let them work in the method most natural to them"?

$\endgroup$
13
  • 1
    $\begingroup$ Welcome to Computer Science Educators and I'm pleased to see a good question from a coder turned teacher. Refreshing. Anyway, a few points to help me understand the situation. 1) Is this something you do for pay, or volunteer? 2) Are the pupils graded, in their primary pursuit, based on what you teach them? 3) Are they graded by yourself with marks which have significance outside your mentoring? 4) Typically, do the pupils arrive with a goal, or objective, already established which you are to help them achieve? $\endgroup$ Aug 30, 2020 at 2:32
  • 2
    $\begingroup$ @GypsySpellweaver Hi, this is for pay, yes. I've had students in high school or college computer science classes - yes we were working on subjects they would be graded on. But more of my students are working independently - they just love to code and want to do it better. I don't grade them. The students in classes have specific topics and goals, but the ones who work independently want to be mentored in coding, just always trying to solve harder problems or work on bigger projects. (Those students are a joy.) $\endgroup$ Aug 30, 2020 at 4:16
  • 1
    $\begingroup$ I have zero background in teaching, but can you find a problem where it's really hard to solve without using functions, and really easy with them? Same for classes. Then don't require them to use functions, just let them figure it out by themselves. $\endgroup$
    – user253751
    Aug 31, 2020 at 15:15
  • 2
    $\begingroup$ And regarding the online judge: make it so if he fails 5 times, he fails. $\endgroup$
    – user253751
    Aug 31, 2020 at 15:16
  • 1
    $\begingroup$ I say this because - as a professional programmer and SO user - I've found that a lot of people are just as stubborn about "being clean" as your guy is about not being clean! They will go through all sorts of weird contortions just to make the code look the way they think their professor would want. Like, they learn the lesson "loops are bad" and then start using Java streams for literally everything. $\endgroup$
    – user253751
    Aug 31, 2020 at 15:17

11 Answers 11

36
$\begingroup$

As someone who has now taught CS for many years, let me first reassure you that teaching clear, clean coding is entirely worthwhile. I think this is especially true for those who will not go off into software professionally, because editing, and being able to express ideas in a clean, clear manner is a skill that serves people well in any field. (I've written a bit about my approach to teaching good coding style before on this site.

Now, USACO is something a bit different. These competitive programming situations are designed for coding speed, program speed, and correct output. You get no points for maintainable code, clear thinking, or reasonable variable names. These contests can be great learning experience as long as the student understands that they are getting intense (and good!) practice on only one small piece of a larger puzzle. I would definitely try to contextualize this for the student, though I caution you that you may never win over this particular student. He may have already become somewhat set in his thinking.

Here's something silly you can do to attempt to demonstrate the value of clean code to the student: take some nice, clean code for a USACO-style problem and introduce an obvious edge-case bug that crashes the program (an array out of bounds or somesuch). Refactor it to give it USACO-style names, like m and pf. Shove everything into main. Make sure that there are no strings to make obvious what the program is supposed to do. Reverse loop styles to make them less appropriate (i.e. switch for and while). Screw up the indentation. Generally make a mess of it. Have fun!

Print out your spaghetti onto physical paper and ask the kid to find the bug. You can even tell him the type of bug. Tell him he had 10 minutes. At the end, ask him what the whole thing does.

Then give him the original version, with clean names, good use of functions, comments to explain what the functions do, and generally clean design. Ask him to find the bug again, and ask him what the code does.

Now tell him that he's just been hired to maintain hundreds of thousands of lines of buggy code that someone else made. If the code all looked like the first example, how long would he give it before he quit that job?

$\endgroup$
13
  • 4
    $\begingroup$ I got interested in USACO a couple years back, but I haven't participated in live competitions yet. So I tend to use these problems for me and students as a chance to develop clean technique. So what about this question: would this slow me down in a competition? Well, some aspects of clean technique take only a little extra typing - you don't need really long variable names, and writing a function in the first place is faster than refactoring it later - and theoretically a clean style would pay dividends in saving or eliminating debugging time $\endgroup$ Aug 30, 2020 at 4:22
  • 3
    $\begingroup$ @composerMike Yeah, I agree. Once you have certain habits ingrained, they definitely help. But remember that you have 4 hours to get your problems done, and (for instance) in Java, they require the entire submission to be a single file with no packages, and they officially recommend not using python because python is slow. They are not interested at all in maintainable code! It's all about (1) speed, and (2) down-and-dirty solving the problem. I've also seen kids get really caught up in USACO and feel like they are really coding and not just puzzle solving. $\endgroup$
    – Ben I.
    Aug 30, 2020 at 12:28
  • 4
    $\begingroup$ @composerMike: You'd be appalled by the number of questions over at StackOverflow where you have to wade through stuff like #include<bits/stdc++.h>, one- and two-letter variable names, and non-standard language "features" because no-one ever taught the kids otherwise... $\endgroup$
    – DevSolar
    Aug 31, 2020 at 15:22
  • 2
    $\begingroup$ @composerMike I don't know about USACO, but I have participated in computing olympiads in my country and similar contests such as ACM team programming contests. At the highest level of competition, there is absolutely no space for "clean coding". E.g., in team programming contests, there are three team members and one computer. The best teams work like this: each team member works independently on one problem with pen and paper. Once the complete program is written down, the team member is given access to the computer and types it in, compiles, and runs. If the program fails (either due to $\endgroup$
    – ciamej
    Sep 3, 2020 at 22:51
  • 2
    $\begingroup$ compilation error, or due to failed cases), another team member gets access to the computer, and the first one, returns to the pen and paper to sort out what went wrong. There is no debugging, and no "refactoring". The code has to do exactly what it is meant to do and has no extra elements that are not necesssary. $\endgroup$
    – ciamej
    Sep 3, 2020 at 22:54
7
$\begingroup$

I emphasize readability and maintenance of code. Therefore, I will assign a project and later turn around and require another student to complete the second half of it. Everyone ends up maintaining someone else's code as a result.

I think you should continue teaching your good habits and thinking styles. That said, you see a student doing Olympiad problems on his own and solving in a way which you would not. Perhaps this is the trade off between readability and maintenance and simply solving a problem in its first draft form. The student you are talking about could of course refactor his code but his interest is in the solution. At any level arriving at a solution is very important. We can talk more on code style and refactoring later.

When it comes to teaching in the classroom, there are curricular objectives to achieve. I outline the requirements and the students are assessed on their performance demonstrating or achieving them. This one function only student may well solve many problems but will not achieve all my objectives. It's also tough to always think of new challenging assignments that require reuse of functions.

$\endgroup$
4
$\begingroup$

Programming vs language

This is the difference between learning to program, and learning a language. It will have analogies in human languages (English, French, etc.) One can know a language, but is one understood; is one poetic; is one concise, is one un-ambiguous.

Does it scale

Un-clean code does not scale. It is like goto and global valuables, they are only bad when the program gets big. OO solves globals, by having small programs (classes) with encapsulated globals, and giving you the tools to join them together. Procedural (and everything that derives from it), gives you gotos encapsulated in for, while, etc.

Evidence

One has to learn for ones self. You can teach what is right, but in the end a student will need to find out for them selfs.

Good examples

Ensure that your examples are clean.

Teaching order

Start with the cleanest techniques:

  • foreach over for or while
  • constants over mutation
  • etc

A challenge that needs recursion

Find an easy challenge that needs recursion. Or at least where the recursive solution is simpler. I use fractal trees (probably not impossible to do without recursion).

$\endgroup$
5
  • $\begingroup$ Great suggestion about recursion. I had that thought when I was doing a USACO problem myself that needed recursion - that's one technique he won't be able to solve without changing his approach. $\endgroup$ Sep 1, 2020 at 8:21
  • $\begingroup$ Can't just about any solution using recursion be recast into an iterative one using an explicit stack or similar structure? (I'm not saying that would usually be an improvement, of course…) $\endgroup$
    – gidds
    Sep 1, 2020 at 14:30
  • $\begingroup$ Recursion might be a little advanced. Plus, you have to use a function for it. Isn't the point of clean coding to choose to write more than you technically must (for readability)? $\endgroup$ Sep 1, 2020 at 19:20
  • $\begingroup$ @gidds: A student who does not understand functions is never going to be able to effectively use java.collections.Stack (or whatever class) unless they are copying and pasting things from Google without properly understanding what they are actually doing. My understanding is, you can't do that in a competition. $\endgroup$
    – Kevin
    Sep 2, 2020 at 0:07
  • $\begingroup$ @Kevin Using an existing function is easier than writing one. Even more difficult is choosing to pull some code into a new function for readability and testing. $\endgroup$ Sep 2, 2020 at 3:29
4
$\begingroup$

Teaching introduces a strong two-way dependency. As a student, one needs a certain amount of trust in the teacher - otherwise, if they already know better, then why on Earth would they need the teacher in the first place. So, if the student is there of their own volition, this already established a need: they need help. The student needs to understand that this sort of a demand originates with them, that they are the one who asked for help.

Once the student-originating demand is established, there comes the teachers job: they become responsible for the progress of the student, as long as the student does what they were asked to do (e.g. doesn't skip practicing an instrument, or does the math problem sets assigned, etc.). This is the strong bidirectional dependency, and it has consequences: the student is always free to do things their own way, but they are free to do it on their own. As long as they are being guided by a teacher, they need to follow the teacher. I'm assuming here that the teacher is competent and responsible to the student's unique needs - I'm far from decrying "put up or shut up", not at all!

In the case you presented, the student simply doesn't know enough to have the wherewithal to make any sort of decisions. And moreover, they already use functions! I'm pretty much sure that their program needs to do I/O, or whatever. So their idea that functions are "not necessary" is a delusion: they are necessary, because they use them. And thus, they need to be able to create their own. If your student insists on doing this "their own way" for too long, you have to explain to them this two-way binding: you can take responsibility for their progress only as long as they trust and follow your advice. If they already know better, they don't need you after all, and you must bid them good-bye. Otherwise, it'll be totally pointless: you'll be frustrated, the student will be frustrated, and on top of it all: the student will blame their frustration on you!

If the student is willing to get frustrated by not following reasonable advice, set them free so that they understand what consequences their own choices bring. You do not want to get involved in such situations - it's totally counterproductive. It doesn't help any that two people get frustrated: if the student wants frustration, let them enjoy frustration on their own.

Teaching is a contract. If either side bails, it's null and void.

It is very important here to note that I didn't even consider the "letting the student do the work in the way most natural to them", since it's a non-sequitur in this case. The student has no way of most natural work at all. They don't nearly have any way of knowing what's natural since they haven't even begun to get the experience needed to explore what comes natural. It's like having a piano student try to tell you what's "most natural" to them after 3 months of once-a-week lessons. It's nonsense. They'll begin to appreciate what feels natural after they've put a few hundred hours of practice in. Same here: There's nothing "natural" to a student that has but a few hours of experience. The whole idea of things being "natural" to such students is based on an absurdly fantastic premise that I can't even begin to understand. Let's not go there. It's a case of being able to write down a sentence, or an idea (that there is something "natural" here to begin with), and then believing it has any meaning just by the fact that you were able to enunciate it. Nope.

$\endgroup$
1
  • 1
    $\begingroup$ These are good comments. I set him loose. Yes, he came because he wanted help, but he rejected every suggestion I made, and even spoke of our different approaches as if they were mere differences in opinion (as opposed to 40 years of experience on one side. I do think there's some validity to the idea of a "most natural approach" - in your piano example, that would be letting the student pick the style of music they want. I also think that there's always a bridge from where they're at to someplace better - it might help to let them cross that bridge at their own pace. $\endgroup$ Sep 1, 2020 at 8:19
4
$\begingroup$

I'll give you a straight, simple, and practical answer. Teach clean coding and simple effective thinking. Because in the practical world, the codes are big and have a lot of integration. The reality is that a single coder does not code all of it. As a teacher, you should teach something that is practically feasible. Teach a student to write such a code that other students can read and understand it.

$\endgroup$
3
$\begingroup$

Learning is like searching for a treasure hidden in the forest. The teacher can teach to use tools that make the task easier, also provides some tips in order to deal with implementation problems realted to the tool's maturity. The teacher should avoid re-invent the wheel, althougth must speak about the history of how it was invented.

$\endgroup$
3
$\begingroup$

Explain and demonstrate the purpose of functions, in context.

Putting everything in main() might work for toy programs, but in real programming you want to use functions for a specific reason: you want your code to be able to repeatedly do perform a particular task, producing a particular kind of output when given a particular kind of input. Depending on the age of the student and their level of mathematical education, you might draw the analogy of mathematical functions, like y = f(x).

One possible way to do this might be to introduce them to recursive programming, but another other way might be to introduce them to APIs and libraries - if you're calling a piece of code somebody else made, it can't be in your main(), and that means that if you're writing that code for other people to use, the code you write can't be in main() either.

$\endgroup$
3
$\begingroup$

Back off on clean coding until they can appreciate it. Take named constants (const int maxScore=14) as an example. Showing const along with regular variables will only confuse students -- why is there a special word to make a variable useless? Later using it to "fix" if(s1>14) will probably still confuse them -- it's more typing and more difficult to see the 14. Wait until they're comfortable with normal variables and are doing longer stuff like if(s1>14) s1=14; with another for s2. The students can now appreciate how a maxScore constant isn't too much bother and makes the program easier to write.

Or take "may get bigger later" functions. Early on, bool win() { return score>=21; } is just going to convince students that functions are stupid -- bools are hard, functions are hard to read -- it's all just a terrible way to write if(score>=21). But if you wait until they know functions better, and when they've seen a single line of code blow-up into a dozen, and they're comfortable with functions inside math -- then it's natural to say "we'll probably want to add more rules for winning, so let's just move it out of the way and into a function".

It might seem obvious to teach naming conventions along with the rules for identifiers, but students confuse the two. Sometimes in their confusion they "fix" syntax errors by making a "more proper" variable name. Instead let them play around with: x, y, count1, count2, A,B,C, number, and hit_points. Let them name functions: f1, function2, and results. At some point they'll naturally become curious how the Pros do it, and what "ways to pick good names" is called.

Decades ago we had a serious cowboy-coder problem. It seemed like new coders were born knowing that obscure (but working) code was how to prove your manhood. We worked hard to stomp that out, but maybe did too good a job. We're not training Jedi's here, where the slightest chink will turn them to the Dark Side. It's fine, probably even good, to let them play with sloptastic coding for a while.

$\endgroup$
4
  • $\begingroup$ Good comments. I want to say, though, about variable names, that I don't think explicit names are the most important part of clean coding. If I have an object of an obvious class Car and I create an ArrayList of Car, I don't need to name that listOfCar. In a small context, I can just name it l with no loss of clarity. In fact I find that short names increase the readability of the code. Clean code has more to do with how it's structured. $\endgroup$ Sep 1, 2020 at 8:14
  • $\begingroup$ This x100. You're just telling them the hard way. Why would they voluntarily do things the hard way? Well, they wouldn't. Wait until it's the easy way, then tell them. Or choose a problem where it's the easy way. $\endgroup$
    – user253751
    Sep 1, 2020 at 18:44
  • $\begingroup$ @composerMike I left out my opinions about naming conventions -- I'll add them $\endgroup$ Sep 1, 2020 at 18:54
  • $\begingroup$ @user253751 Hmmm ... my short description has problems and solutions -- not showing a feature that solves a problem they haven't had yet. I think easy-way/hard-way might be a neater way to express the same idea. $\endgroup$ Sep 1, 2020 at 19:11
2
$\begingroup$

What do you mean your students are not going to become professional coders?

Is your education only meant to become a hobby for them? You mentioning coding competitions seems to indicate that this is the case.

I think what you really meant is that these people will not be full-time programmers but that they will program as part of their jobs. People in this sort of job (scientists for example) are very often producing the most horrid and unreadable mess of a codebase you could imagine. I believe the culprit is that they had no real formal education in programming other than "how do I get it to do what I want".

The vast majority of people who code for a living and are educated in how to code will value readability above absolutely everything else, probably like you do. For people who have the experience of working with large codebases over long periods of time and the knowledge of how to make this easier, making it easier is their number one priority.

The problem then is people who have to maintain large code-bases over long periods but don't know how to make that easy. Or in fact, don't know that it is at all possible to make it easy. I suspect part of your job is to teach people who could find themselves in this situation in the future.

Kids doing short puzzle-like programming exercises will almost certainly believe that the right metric to evaluate whether a piece of code is good or not is speed or memory usage or even brevity. It is therefore your responsibility to teach them that the one thing that matters the most in code is whether the code communicates its ideas and intent effectively. That is admittedly a much harder thing to teach, because not everyone will accept your arguments. It's a bit like teaching a toddler that fire is dangerous: they believe you, but still have to try by themselves.

I like Human Resource Machine just as much as the next person, and it is frankly an amazing game, but that's all it is: a game. One person's ability to solve programming puzzles and their value as a programmer in a real life scenario are borderline unrelated. I'd say it's totally ok to indulge in a little bit of puzzle-solving and I think it's very likely more motivating for the students. But fundamentally if you don't focus on larger scale projects then you will fail to address the real problems.

If you really succeed and can follow these students over multiple years then at the end you should be able to reach several higher level concepts. First, that there is beauty and elegance to be found in code. Second, that elegant, simple and beautiful code is much harder to write.

Much too often people have this almost unconscious rule in their head going "if it was difficult to write then it should be difficult to read". Almost all programmers went through a phase at some point (some never escape it) where they think writing complex code using obscure functionalities is a demonstration of their coding prowess. You have to dispel that idea and confront it openly. It's when code reads like it is self-evident that it was most likely the hardest to write, much like writing a research paper or a book.

$\endgroup$
1
$\begingroup$

There will come a day when a problem is too hard or too large for him to solve on his own (of course). He is being academically lazy and it will handicap him. Thats a common pitfall for bright kids. It's totally OK to experiment and 'go your own way' when learning for the first time. Learning should be fun. It will help him relate to new information he receives and put it into some context. Play helps people become interested. Work is what guarantees long term success. Allow for play, but don't let him break his own legs.

Its your job as someone older and wiser, to make sure kids don't hurt themselves when they play.

$\endgroup$
1
$\begingroup$

I'll probably get some hate for this, but I personally hate coding in classes and Java in general, it's just not my cup of tea. But I can appreciate good, clean code. I program mostly in php and this makes the use of proper classes less important, as you can just physically separate it into separate pages. But I understand when classes are necessary/use-full. It might be a good idea to show him coding in unity, or similar, as that is a case where classes are very useful and arguably even necessary.

$\endgroup$
4
  • 1
    $\begingroup$ The use case we had for classes was to make a list of objects and sort them by one of the object's fields. He had written his own sort algorithm, inside a for loop no less adding complexity - instead of just using Collections.sort() $\endgroup$ Sep 1, 2020 at 8:11
  • $\begingroup$ @composerMike It's good if he understands what a sorting algorithm actually does, not just being able to use Collections.sort() , though it is really odd not not use it if it is available. If he is into math it might be a good idea to tell him about the different kinds of sorting algorithms, and challenge him to create an efficient one, that he could use if future, like the Collections.sort function. Might be fun for him. $\endgroup$
    – The_Moth
    Sep 1, 2020 at 10:41
  • $\begingroup$ @composerMike when you said he didn't want to use classes I thought he just didn't like the idea of not putting all of the code into main() and having to call it, which is a sentiment I get, if the task is sufficiently simple. $\endgroup$
    – The_Moth
    Sep 1, 2020 at 10:44
  • $\begingroup$ His data was a list of groups of three integers. He had three ArrayList<Integer> and wrote an algorithm to sort by one of the integers, requiring him to move the other two along with them. What he could have done was put the three integers in a class C and implement Comparable, then use Collections.sort on ArrayList<C> $\endgroup$ Sep 4, 2020 at 23:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.