<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'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 "App" to them (ex. middleware/middleware.go).</p>
<p>Is this the best style? For example, in all routes I have ugly "rh.App.DB.Topics" type lines which don'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 "Wrap" method and pass in the "App" 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'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't matter. You'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'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 "I'm not using a framework, honest!" and then iterating a list of dependencies, Gorilla stuff being the most frequent, isn'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't need to be in a struct, they're just functions.</p>
<p>If you're doing a big app (and likely if you aren'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 "use cases" 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'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'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
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传