Making live programming practical by bridging the gap between trial-and-error development and unit testing