It looks like most of the errors in your image are due to the lack of one critical property. That is that, for any edge (two out of three vertices of a triangle), the rasterization algorithm must have a consistent opinion on which side of the line each pixel falls on, even for different triangles, if those triangles share an edge (have the same vertex coordinates for 2 vertices).
For example, on the blue face, you have two triangles forming the surface. There are visible gaps, which indicate that the two blue triangles are not meeting perfectly at the edge, which happens because the two rasterizations are not agreeing on which triangle is responsible for filling a given pixel — there's probably some overlap (which is invisible) in addition to the gaps.
Fixing this should also help with the yellow edge on the right and the wiggliness of the red-green edge.
(I do not have any advice on how to implement this property in rasterization, as I haven't dealt with triangle-based software rendering myself; I just know it's necessary.)
Additionally, you should implement “back-face culling”: do not draw a triangle if it is facing away from the viewer. Facing is usually defined by triangle “winding order”, clockwise or counterclockwise; one way to understand this is that you take the first two vertices of the triangle as a line with a direction (in screen space), and ask whether the third vertex is to the left (CCW order) or the right (CW order) of that line. That turns out to be equivalent to asking which face of the triangle is being viewed; you pick one such face to not draw, and make sure your mesh's vertex ordering matches that choice consistently.
When you have done this properly, the yellow back-face will not be drawn at all.
I'd recommend fixing your rasterization first, because implementing back-face culling will hide some of the problems. But culling will give you a big speedup since you can stop rendering half of the triangles in the scene (typically).