OK, first welcome and hello 
About what you’re trying to do, you don’t need to perform any checks about the balls’ y coordinate. You said there’s a bucket, right? - just like a basketball game - that bucket should have a collider (box collider is ok) within it, make sure to check ‘is trigger’ on the collider, which means it won’t intercept / physically collider with whatever comes through it - in other words, anything could pass right through it. Now whenever a ball gets into the bucket, it collides with that collider, and since you ticked ‘is trigger’, OnTriggerEnter gets ‘fired’ (OnTriggerEnter is an event - when you hear an event got ‘fired’ it means the event has happened or occurred, if you like) - Now, you will ‘handle’ this event in your ball script, like:
OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == Tags.bucket)
{
Debug.Log ("ball " + id + " is inside bucket"); // assuming you have an id for your balls, which could be a name, a number, etc
}
}
You don’t have to handle it inside the ball, you can do it in the bucket script if you like:
OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == Tags.ball)
// do something...
}
This is from a basketball tutorial I went through when I was staring (I don’t wanna give you links to, because their code quality just SUCKS!)

Note that, in my case, I have to make some checks to make sure that the ball goes in the basket from top to bottom, and not the opposite. But since you’re using a bucket you don’t have to because it’s sealed from the bottom.
Now, you mentioned good habits? - here’s a few:
- NEVER use statics unless you know
what you’re doing. When you make a
variable static
it means that
ALL instances/objects of your class will
share/have the same variable. When to
use this? - let’s say you wanted to
make a ball id (integer), each time
you instantiate a ball, you give it a
new id (assuming that you don’t
destroy them, they will keep their id
unique) - how would you do that?
A simple way is using static variable to count how many balls do we have, use the value of that counter as our id, like so:
public class Ball
{
private static int counter = 0;
public int Id { private set; get; } // this is a property, anybody can 'get' its value, but only inside this class, that its value can be 'set'
void Start()
{
Id = counter++;
}
}
This is OK, it makes sense for all balls to have the same counter, right? 
With the previous code, first ball gets instantiated will have an Id
of 0, 2nd one will have 1, then 2, 3, 4, etc. This is because counter
is static, it will remain the same between all ball instances. BUT, why didn’t I make Id
static? o.O - Ask yourself: “Should all balls have the same Id?” - Of course not! otherwise it’s not an identifier that I could identify a ball with - it’s like you’re saying all the balls are the same 
This is exactly what you did with:
public static float speed = -8;
public static float ballYPosition;
That way, all balls have the same speed
and ballYPosition

Another good example of statics: It’s always best to organize your tags in your game, keep things in one place and not scattered around. Because what if you changed your tag? - you would have to go and change it in numerous places. The way I like to do it, is to use a “Tags” class - It’s a class that I always like to use to store all my tags. A Tags
sample class would be:
public abstract class Tags
{
public static string bucket = "Bucket"; // you can use static instead of const
public static string ball = "Ball";
public static string player = "Player";
}
(abstract means that you can’t make an instance of your class = you can’t instantiate objects of that class - this is good for our purposes because we are intending to access the members of the class in a static manner)
And then you can access your tags in a static manner as we mentioned, like so:
if (collider.tag == Tags.player)
{
// do something
}
You don’t need an instance of the class to access a static variable, just nameOfClass.myStaticVar;
- Which makes sense. There is a bit more about static variables, I will leave learning their basics and googling to you, but for example.
More about usages of static variables within Unity (great example!).
- Give your variables self-explanatory
non-confusing names. Like your
positions
variable. A rule of
thumb: Always try to make your
variables identifiable by their
names. By identifiable I mean someone
can easily tell what they serve and
what’s their purpose. And sometimes,
good naming could lead to the
discovery of the data type of the
variable. On the contrary bad naming will lead to confusion. For me when I saw
positions
I immediately thought
it’s either a list or an array of
Vector3.
There’s a lot that I would love to cover for you
- But I think it’s best to learn from some good tutorials. Please understand that there are a TON of shitty ugly disgusting crappy tutorials EVERYWHERE! - Just make sure you choose the good ones, ones that are tutored by ‘good’ programmers, who write good quality good, there are a lot of course.
-
Programming-related: LEARN OOP!
And get your basics together just
right.
-
Unity-related: I have a few,
Quilly is very friendly to
new-comers and explains things just
right! (basic-intermidate, uses C#) - Then you got
BurgZergArcade, great
programmer! Got an extensive
400-videos RPG series! (Basic, intermediate, advanced, uses C#) You Got
UnityGems which I mentioned
earlier (a bit more advanced stuff).
You can’t go wrong with these guys,
anything they say is like sacred!
(Intermidate-advanced, uses C#)
Then you got Brackeys (Basic-intermidate, not sure about lang) and Etiskee (Basic-intermidate, uses JS) for FPS-related stuff. Great, but not very technical. Finally thewalkerboys (Basic, uses JS) and thetornadotwins (Basic, not sure about lang)
Lastly, what are you doing with:
private object WaitForSeconds(float p)
{
throw new System.NotImplementedException();
}
WaitForSeconds is already implemented for you, unless you don’t want to make something like, WaitForRealSeconds
I don’t think you need to bother yourself with re-implementing it 