There is a point where you should award some marks for the code being complete and producing the output. If the code is only part of the assessment and the student was not capable of writing it themselves, then the other elements are likely to be of low quality. It is reasonable to assume that correct code in many cases should look similar, so to award a Zero would mean you are certain that plagiarism or collusion has occurred, in which case you should have no problem defending your assessment.
Most institutions would have a clear policy around plagiarism, if you have such a policy then when there is a dispute or challenge to your assessment on the grounds of plagiarism you need only to remind the students of the policy, that policy should guide you on both how it is detected and what the penalties are.
- If you do not have a policy on plagiarism, then be sure to establish one, even if it is a preference that might be hard to enforce, make it clear before the assessment task that plagiarism and collusion are not going to be tolerated.
One strategy to discourage plagiarism in programming is to encourage creativity, by requiring students to design their own models and scenarios and even the test harnesses to demonstrate certain techniques. It takes a lot of work, and you can't rely as much on automation for reviews, but even if the students source blocks of logic from SO or each other, if the models they are applying the logic to are unique then they will still have to understand the code to make it work.
You can also complete an assessment over time, or turn submission into more of a folio of work, apart from making it easier to detect plagiarism as the complexity of the assessment content goes up, you can lower the bar in terms of effort required by the student, especially if there is a chance to complete the tasks during class times.
As to how to help the students improve when they are caught out, give them the opportunity to re-submit, but this time give them a different assessment item. With different requirements they can not simply re-write the syntax from the previous submission, they will be forced to think about it even if they are going to apply some or all of the code in the first assessment.
- A simple trick here is to change the subject or topic of the content. This will actually help you identify if they understand the difference between encapsulating abstract concepts and the business domain concepts.
Whilst facetious, it must be recognised that the point of learning is not to re-invent everything, but that we should continue to evolve and build upon established concepts. This is true for programming as much as other domains. The reality of how programming is applied in commercial contexts is that there is a lot of skill in locating and understanding the correct pattern or solution to apply to a logical problem domain and how to implement it correctly.
- In layman's terms this is effective use of
A good developer does not re-invent the wheel, they determine how to fit the a standard wheel implementation into their model.
I can't help but share my favourite quote from Eric Lippert:
The notion that programming can be principled — that we proceed by understanding the abstractions afforded by the language, and then match those abstractions to a model of the business domain of the program — is apparently never taught to a great many programmers. Rather, many programmers proceed as though they’re exploring an undiscovered country, and going down paths more or less at random and hoping they end up somewhere good, no matter how twisted the path is that gets them there.
It is true there may be a unique solution to every problem, the construct of institutionalized education is such that many problem statements used in assessments have been used before, so avoiding plagiarism from sites like SO would require your assessment criteria itself to unique. Try assessing Fizz-Buzz in a room of students with no external communications, depending on how you have taught the concepts there is likely to be a strong commonality in the style, layout and logical expressions utilised to produce the result. Programming is very logical, just like mathematics there are right answers and many that are clearly wrong. But the processes used to work out the result will be influenced by the tuition and other experiences of the student, if all their experiences and learning is shared or taught from a common source, then it makes sense that the outcomes would be similar from students across a class or cohort.
Although not very practical, to determine plagiarism, you should be looking for the personal quirks of one student to be reflected in the others, try comparing the mistakes or omissions, as opposed to the correct elements. Or the reverse, that the quirks of the submission are not consistent with any previous work from that same student. If in the other elements the student has demonstrated a genuine understanding of the code, and an ability to recreate it if given ample opportunity, then whilst you can disapprove of it, without stronger grounds or investigation it should be marked according to its content.