readability
See first the articles on commenting, indentation, and white space. Code needs to be readable so that readers, who might be you in a few days, or you in six months, or another programmer in six months or six years, can readily understand what you are trying to do.

Perhaps the first principle is to use meaningful and accurate names for variables and predicates. If your predicate is supposed to check if a number is even, you can call it is_even. If you later change it so that it also calculates the contribution, for the case of even numbers, to some total that you are calculating, then you need to change the name of the predicate to reflect this. Maybe you can call it even_contribution, and put a comment where the predicate starts, stating exactly what the predicate does, in more detail than you can fit into a predicate name.

Don't reinvent things already available in Prolog.
Here's an example of some code produced by a novice Prolog programmer:

mymember(First, [Second | _]) :-
        member(First, [Second]).
First of all, member(First, [Second]) is identical to First = Second. So why not say so:
mymember(First, [Second | _]) :-
        First = Second.
But then, why have the explicit unification of First and Second - so instead:
mymember(First, [First | _]).
At this point, we can see that mymember is a misleading name for this predicate - which is actually checking whether its first argument is the same as the first member of the list that is the second argument. So the name of the predicate is misleading, as well as unclear. member, in Prolog, means check the whole list for the presence of the first argument, whereas this predicate only ever looks at the first element of the list. The work that this predicate is doing has no obvious name, and that suggests that it is not a useful abstraction of the problem being solved. The problem that the novice programmer was trying to solve was to find out if a list had successive elements that were the same, as happens for b, but not a. in the list [a, b, b, c, d, a]. So a better way would be like this:
has_repeats([]) :-
	fail. % unnecessary rule - see below
has_repeats([_OnlyOneItem]) :-
	fail. % unnecssary rule - see below
has_repeats([First, First | Rest]).
has_repeats([First, Second | Rest]) :-
	First \= Second,
	has_repeats([Second | Rest]).
In this code, the rule in red is the one that corresponds to what the novice programmer was trying to do with "mymember".
Notice also that the rules using fail can be omitted - they are only there to make it clear what happens with empty lists and lists with one member.

Don't have unused "junk" code. Obviously, it is worse still to have used junk code - that is, wrong code. However, unused junk code is confusing for the reader and demonstrates that the programmer who wrote it was confused. So how can you tell if code is unused junk? The best way, I suppose, is to have a thorough understanding of the code you are writing, and then you'll see that the code is junk. Failing that, when you test the code, you can put in calls to the built-in Prolog predicate print, at the start of any rule you are unsure about.

thing(X, Y) :-
	print('Entering rule 3 for predicate *thing*'),
	... % rest of goals for this rule
	.
Then you try to generate a test case which will make use of your rule in finding it's first solution:
?- thing(A, [cat, dog, mouse]). % replace with actual parameters
    % that are supposed to test rule 3 of the predicate called thing
A = 3.
If, as in the example dialogue, the print never executes, or never executes as part of a successful search for a solution, then it's probably junk.