First of all I would recommend to read about the Testing Pyramid (if you do not know it yet); in a nutshell, do not create more than 10% GUI Tests.
Furthermore, I recommend these two articles from Gojko Adzic:Ui Testing without shooting yourself and Effective User Interface Testing
In our current project we (unfortunately) have a lot of GUI Tests. What helped us a lot to get those more stable and reduce fixing time, is to raise the level of abstraction. First, you have your page objects (one object is dedicated to one page/tab). After that, create workflows that represent a certain functionality and thereby can be reused in several tests, e.g. Login.
GUI tests tend to take more time to complete, so if something happens at the very beginning, it might be possible that it still fails after 10 minutes (timeout). Therefore we introduced checkpoints; those represent a certain state (e.g. in the database) and have to be reached after a defined time. E.g. one checkpoint polls the database for the field "order" and if that field is still empty after 2 minutes, the test fails. Thereby you save time by failing faster.