First web app in Go - Need some advice

blov · · 448 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi <a href="/r/golang" rel="nofollow">/r/golang</a>!</p> <p>I am writing a web app for a University research project in Go. The project can be found at: <a href="https://github.com/UmairIdris/uTeach" rel="nofollow">https://github.com/UmairIdris/uTeach</a></p> <hr/> <p>I read <a href="/r/golang" rel="nofollow">/r/golang</a> extensively and researched online quite a bit and have the following technologies in use currently:</p> <ul> <li>No framework, only net/http</li> <li>Gorilla mux for routing</li> <li>Gorilla sessions for cookie sessions</li> <li>sqlite3 for db</li> <li>No ORM, just sqlx to get model structs from the db </li> <li>Alice for middleware chaining</li> </ul> <hr/> <p>Initially, when I was developing the app everything was in the main package. Also, everything was a global (db, templates, sessions, etc). This made it easy to get things started. However, as the app was growing, I noticed that the files were getting quite large and being in one package + using globals was harming the modularity and testability of the app.</p> <p>I decided to try and do some heavy refactoring. The first step was to use an AppContext (I just called it App) as explained here: <a href="https://elithrar.github.io/article/custom-handlers-avoiding-globals/" rel="nofollow">https://elithrar.github.io/article/custom-handlers-avoiding-globals/</a></p> <p>This worked great, the app did not rely on globals anymore, however everything was still in one package. I tried to put each piece in its own individual package. However, in Go you can&#39;t add methods to a struct defined in another package. So, for routes and middleware packages, I need to create a whole new struct and pass in the &#34;App&#34; to them (ex. middleware/middleware.go).</p> <p>Is this the best style? For example, in all routes I have ugly &#34;rh.App.DB.Topics&#34; type lines which don&#39;t read elegantly at all. </p> <p>Possible solutions:</p> <ul> <li>Use embedded structs, but I am not sure if it logically makes sense for app to be embedded in a route handler or middleware.</li> <li>Use a &#34;Wrap&#34; method and pass in the &#34;App&#34; as a parameter for route handlers <a href="https://www.reddit.com/r/golang/comments/2apjja/passing_context_to_interface_methods/" rel="nofollow">example</a>. However, this breaks the net/http interface.</li> </ul> <hr/> <p>If anyone has tips on how to improve the design of the web app, or if they have any tips/advice for the web app please let me know! I really appreciate you taking the time to read all this.</p> <ul> <li><p>Note 1: Currently most packages only have 1 file. I will split them up into separate files with logically grouped functions so it is easier to read once I have to structure of the app down right.</p></li> <li><p>Note 2: Currently if there is an error I simply write it to the page. This will leak sensitive information. It was more debugging ease for me, but I will replace this with proper logging in the near future. </p></li> </ul> <p>Thanks!</p> <hr/>**评论:**<br/><br/>birdsaresodumb: <pre><p>Gorilla&#39;s context package is excellent. You might start there. Also, check out <a href="http://go-bootstrap.io/" rel="nofollow">http://go-bootstrap.io/</a> Cool tool that lets you generate some code for your project. Whether you use any of the generated code doesn&#39;t matter. You&#39;ll learn a lot just from reading through the approaches used there.</p></pre>birdsaresodumb: <pre><p>Just wanted to note that you will find a lot of similarities in your current code and what you&#39;ll get from go-bootstrap.</p></pre>leoumair: <pre><p>Brilliant! Thanks so much... go-bootstrap sample project answers pretty much all the problems I was experiencing! I will try to modify my project to more closely match their sample. If only I found this sooner!</p></pre>karnd01: <pre><p>I started out using most of the same components you did and also struggled with the best way to handle passing the app context around as well and ended up creating <a href="https://github.com/go-playground/lars" rel="nofollow">https://github.com/go-playground/lars</a> which specifically allows passing of an AppContext </p> <p>it is also compatible with the standard middleware and handlers and handles the chaining for you as well</p></pre>blueblank: <pre><p>I recently refactored <a href="https://github.com/thrisp/flotilla/tree/develop" rel="nofollow">flotilla</a> to separate packages, cleanup and finalization pending. It uses an Application as starting point/bucket to hold all the things you need with a State/Context that gets passed through all handlers which is fairly common pattern. It is just something you need to work with and it gets clearer. If you are passing a handler to a different package you can just wrap the handler in a local handler as a function that returns another handler. </p> <p>Just as an aside, saying &#34;I&#39;m not using a framework, honest!&#34; and then iterating a list of dependencies, Gorilla stuff being the most frequent, isn&#39;t really that pointed out as being an anti-go pattern, but I personally think it is and its a pattern that occurs a lot with people discussing their go web stuff. It is contradictory, and no one ever points that out, just my two cents. </p></pre>mixedCase_: <pre><p>First of all, let it be known that I only took a look at your folder structure and a random file, I may be making some wrong assumptions.</p> <p>Your handlers don&#39;t need to be in a struct, they&#39;re just functions.</p> <p>If you&#39;re doing a big app (and likely if you aren&#39;t as well) I would suggest you to cleanly separate your concerns. The package that does the routing should probably not talk to the database. You should have it talk instead to a layer that contains all the &#34;use cases&#34; of your application, containing validation and other logic, which then delegates object storage and retrieval to another layer (think of it as some sort of repository pattern).</p> <p>And if you&#39;re in doubt where a reference should live, parametrize. If it belongs in (a struct inside) a package other than your main, it should become obvious as you make progress and it&#39;s a little refactoring away to do so.</p></pre>leoumair: <pre><p>Thanks for the feedback. You made very valid comments. After taking a look at go-bootstrap which <a href="/u/birdsaresodumb" rel="nofollow">/u/birdsaresodumb</a> suggested, I see the models are initialized with a db and the models control the access to the db not the handler, which I will try to emulate.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

448 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传