Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revel (considered harmful) #1193

Open
brendensoares opened this issue Jul 5, 2017 · 11 comments
Open

Revel (considered harmful) #1193

brendensoares opened this issue Jul 5, 2017 · 11 comments

Comments

@brendensoares
Copy link
Member

This is a open reply to a question raised in a go-kit issue which was locked preventing direct response. @fluxibox @peterbourgon @adamjacobmuller

First, it should be clear, that I'm the current maintainer of Revel (along with @notzippy @pedromorgan @shawncatz), so I am biased.

I've been told many times that Revel is less than ideal as a Go-based web app development framework and instead you should use another framework that is "more idiomatic" (or roll your own framework and use net/http).

Why would this be said of Revel? After all the idioms of Go are still being actively developed (which is to be expected for a young language). However, when taking Revel for a spin for the first time you'll notice a few things:

  1. It expects you to use the revel tool (which enables rebuild on file change, binary packaging, etc)
  2. You don't need to create your own main() as the revel cli does it for you as part of the build process (so that it can auto register your controllers and methods)
  3. You embed the revel.Controller struct from the Revel package to gain a "context" into the request/response flow

Some people don't consider this pure i.e. idiomatic Go. They don't appreciate the "magic" that happens when following these conventions; they like to understand exactly what is happening under the hood at all times.

Others who view these choices as assets instead of liabilities appreciate being able to have a standard project file structure, rapid development time, and reduced boilerplate code.

Not that Revel uses Dependency Injection in any major way, but DI is actually a great pattern to use to make your code more modular and testable. Also, many others are interested in applying DI to Go and I can't find any critics of DI in Go or anyone claiming it as not idiomatic. The same applies to IoC.

In my own experience, Revel works great with DI. I've also been using DDD (Domain Driven Design) principles with Go and Revel. My Revel Web App has a app, infrastructure, and domain layer as well as a versioned, Restful API.

I'll stop here, even though there is a lot to be said about the evaluation of Revel as your choice of Go Web Framework (reflection, code generation, using FastHTTP instead of net/http, writing your own main(), integrating Revel with another Go app, performance, conventions, etc). I simply wanted to make an objective reply (as much as that is possible in my role) to a hollow accusation (can we give some substance to the claim?).

I'd love to hear more on this topic from critics and fans alike. My mind is open.

PS - I was personally looking into go-kit to compare approaches of developing microservices in Go when I learned that Revel is considered harmful. I'm still looking into it, because perspective is valuable and I acknowledge that I know nothing.

@jeevatkm
Copy link
Contributor

jeevatkm commented Jul 5, 2017

@brendensoares You have expressed it objectively and clear. Thanks.

@adamjacobmuller
Copy link

Thanks for the reply @brendensoares, appreciate the information and the very level-headed response.

@pedromorgan
Copy link
Member

IMHO this is a storm is a teacup, your coffee MUST be pure ground, not instant, the TIP must be green...

As a hacker, I use golang cos it nice break from the subtle bugs on my systems.. I dont care if its not "pure go"... does the job, and that all i want,, and as today, get home and have spare time to add a comment to this issue... So it works for me big time..and logic is abstracted away in a module, that relly I could replace overnight with "something else"..

Revel gets me up to speed and fast.. generally using py+bottle for dev and then into golang/revel.. Even the mobile developer loves go, cos it makes sense, unnlike the python stuff

@pedromorgan
Copy link
Member

Maybe we need a counter with "why revel sucks".

  1. does recomiple on the fly
  2. a test suite
  3. compile a binary and done
  4. go home early, I didnt have to write my own framework to solve problem..
  5. isnt idimatic go, uses some tricks to create things.. But hey.. ask the designers. og go..
  6. otherwise stick to php7 or c# or even...

@Fyb3roptik
Copy link

I use Revel for an API that transacts millions of records daily. This framework is awesome and I have helped contribute to it!

@ryandavs
Copy link

I haven't used Revel but I have been watching its development since its early release. I am really looking forward to be using it in my company when it gets approved.

Here's my version of "13 Reasons Why"... I think Revel rules?

  1. Familiar (Rails-like)
    The Rails, Grails, Code-Igniter, and similar Rails-like approach to MVC are not going anywhere. In fact, these frameworks have been flourishing without any sign of becoming the next "legacy" or abandoned framework. The reason is simple: that this pattern really works and it saves developers and companies time and money.

  2. Convention over Configuration
    I hate configurations. Period. I know we can't completely get away with configs, so I would tolerate a minimal configuration. Revel ticks that checkbox.

  3. It's a framework
    And it means that as long as I follow certain rules, I don't have to deal with debates and dilemmas like project/code structure. Tell me to roll my own framework and I will tell you to go f*ck yourself.

  4. Hot code reload
    I don't know about you, but you're a masochist if you love the idea of manually recompiling every time you change your code.

  5. Drupal no more - I have been detoxed and I'm free - never again
    Other existing Go Web frameworks, and even in Go's own doctrine, encourage a Drupal style of framework--that happy moments of your life where you define the routes, hundreds of routes, and point it to functions of your choice, yes hundred of functions to choose from. Just name your functions intelligently or else you will have to rely on your IDE's "find" feature (just pray that you won't have hundreds of search results). You know that happy moments where each developer organize his own functions (which php file to put it, and which folder to put this php file, and which other php files this function depends on), and what the heck is that route again, and you end up debating with your co-developers who has the best approach to follow, and the code review hell that follows, and that you need to convince the team lead that it's time to write a guide book because you've been scratching your head about this mountain of code mess, you need a guide book, a convention manual that nobody has time to read. Believe me, if you patterned your framework to be like Drupal and your website plus its internal management systems has grown to be bigger than a blog site, you would hate your job and you would curse the day you were born. Never again.

  6. Toolkits like caching, validation, form processing, etcetera

  7. Caching

  8. Test Framework

  9. Internationalization

  10. Revel Jobs

  11. WebSocket support

  12. More time for shopping and for my family

  13. More time to watch Netflix' "13 Reasons Why"

@jimmy-go
Copy link

Hi @brendensoares, this is an old debate and I don't use revel anymore but clients of mine do. I did use it by 2 years so here are my two cents:

  1. Why idiomatic Go?
    Well, my first time using go was simple and graceful (fucking awesome!!).
    Then I change to another job where they used revel. I feel like it was taking all the advantages from Go and making it feel like php/java :S.

1.1. Imagine someone speaking bad english on purpose just because he feels it's fine. That's happens with idiomatic Go, the development team has made conventions, (and more!) in order to prevent headaches for newcomers and veterans.

1.2 Framework vs toolkit. Having the chance of replacing some part of your code when needed is agile enforced. But when you hit the framework limits then you are in troubles. And that's the point about a framework, all eventually reach a limit on flexibility and backwards compatibility that tries to fix with next major releases.

  1. Revel hot reloading feels awkward.
    When using go build or go run you know when the code is compilable.
    But with revel hot reloading it forces you to open some web browser (or run some curl command) just to know if it runs.

  2. Taking main.go from the developer's control is like removing a book's index pages.
    You need a starting point in order to let the developer know what the project is all about.
    Where can I view the overall structure of a revel project? Some people use app/init.go to kickstart third party connections. There is a revel way?

  3. app.conf TOML format is bad, really really bad.
    Makes the developer and devops team use 2 flags only to know what environment wants to run.
    Compare this 2 cases:

myBinary -config=dev.yml

vs

myBinaryRevel -config=app.conf -env=dev
# Some people even do this:
myBinaryRevel -config=app.conf -env=dev -db=someDbURL

When you open the config file you need a large monitor just to know what is going on.
I don't say yaml is perfect but is more readable in less space and prevents developer mistakes when setting flags.

  1. Router file in plain text.
    Why can't I jump to function from my routes file? Because is taken away from the developer/IDE/text editor control and requires another dependency (revel) for parse and code generation in order to work.

  2. Modules.
    It's a nice feature but most developers merge all the backend functionality in one repo because they think easy equals better, but that means some module can crash the server and lower the uptime. Even worst some module can be taking all the system resources and leaving the principal part (the REST API) irresponsive.

  3. Newcomers think revel is the shit and is all Go can offer.
    I have seen too much people giving Go a try and using revel as his/her first framework. The problem with that (apart from 1-6) is that they feel confortable and don't give a try for other solutions. It can stops the developer curiosity from growing.

Sorry for been rude but these problems can be fixed as I see it.

What can I say about how to made revel better?

  1. Use main.go for all the tasks that app.conf and routes file does.

  2. If you really really want hot reloading then embed entr inside revel (a simple script can do the job too).

  3. Made clear in the wiki what CAN, CAN'T and NEVER will be revel used for.

  4. Use yaml or json or any other format that can be simple and don't have the TOML format issues.

  5. Some great value can come if you add gometalinter or similar to revel workflow.

It's easy to say do that I know, so thats why I will try to implement some of these features by myself and see if works.

My best regards.

@notzippy
Copy link
Collaborator

@jimmy-go Thanks for the feedback, and the points for making Revel better.

The Go way is idiomatic, that is the whole idea behind Go. But it does not make you think about code organization until you realize that hey maybe that file that is 2000 lines long should have been split into two, and now I need to worry about packages and crap if I am moving stuff now I got circular references and ¯_(ツ)_/¯ . Revel forces you to think about planning your package layout at the beginning which is what a lot of beginners need. Do advanced programmers need this, likely not as much but I find it convenient that Revel does a skeleton layout for me.

The revel command actually mashes together a set of multiple Go commands. Here is what it does and the Go equivalent command

  1. Start a proxy (Just for the browser aspect)
  2. Building a main file from the code, this is very similar to go generate function - and has the same purpose, let the machine generate code that the machine needs and the humans only need to deal with higher level code.
  3. Compile the code - this is a convenience method to go build
  4. Check errors in code, if an error in the code is a missing package error do a go get missing.package - repeat step 2
  5. Run the code connecting the proxy to the port the code is running on, pass in the path to the application (so templates can be found), pass in run mode (dev, prod or other) yourapp your_app_path run_mode
  6. If the compiled code has errors display the errors through the proxy (and related file)
  7. Monitor for any source file changes, if code is changed restart at step 2
    I am looking at breaking this process out, but you have to admit it saves a bunch of steps.

I agree with the framework vs toolkit issue, and part of the series of the latest releases was to make Revel more modular internally. Currently the server and template engine have both pluggable architectures. which avoids the issues you have with typical frameworks were you "hit the wall" with the configuration options available. Revel could communicate on an RS232 port now if you wanted it to.

The config, routes, those are in the crosshairs to be dealt with in a different manner.

My 2 cents :-D

@anthonyraymond
Copy link

anthonyraymond commented Jul 11, 2019

Coming from a java (spring) world i feel familiar with revel already with just a quick look on documentation. It looks straightforward but also required some understanding of the magic behind (just like spring framework). It may or may not follow the more idiomatic, but i like the way it is.

But i strongly share @jimmy-go point of view on the main.go file, i don't want a framework to generate the main.go file for me, it's my entrypoint and i may want to run some stuff in it before revel even fires up. adding such routines in init() feels hacky and make not much sense.
I'd prefer writing redundant code on each projects to fire revel instead of having my entrypoint kidnapped.

I'd be pleased to use it for all the cool stuff and convention that comes with it, but the lack of main.go is a no-go for me 😢

@notzippy
Copy link
Collaborator

To be fair... @anthonyraymond Hooks have been added (https://revel.github.io/manual/startup-shutdown.html#revel_event_hooks) allowing you to hook into the startup of Revel subsytems, and as always you had the OnAppStart (https://revel.github.io/manual/startup-shutdown.html) OnAppStop callbacks to perform whatever is needed on start or stop of the application. It would not be to difficult to include a setting to not include a main file but to use file XXX as main, because now the main generated file has been reduced to the following

// GENERATED CODE - DO NOT EDIT
// This file is the main file for Revel.
// It registers all the controllers and provides details for the Revel server engine to
// properly inject parameters directly into the action endpoints.
package main

import (
	"flag"
	"github.com/revel/examples/booking/app/tmp/run"
	"github.com/revel/revel"
)

var (
	runMode    *string = flag.String("runMode", "", "Run mode.")
	port       *int    = flag.Int("port", 0, "By default, read from app.conf")
	importPath *string = flag.String("importPath", "", "Go Import Path for the app.")
	srcPath    *string = flag.String("srcPath", "", "Path to the source root.") // Optional

)

func main() {
	flag.Parse()
	revel.Init(*runMode, *importPath, *srcPath)
	run.Run(*port)
}

@anthonyraymond
Copy link

hi @notzippy thanks for your answer.

I've seen the hooks and OnAppStart already, but i i does not fit my use case, i want the webserver to a subcomment of my app, not main thing. It is suppose to started (or not) based on the outcome of the init process. There is some cases where i want my app to be running but without the webserver.

I must admit this is not a regular use case. But go-gin supports thanks to the exposition of the start and shutdown method. Having that said, if you release this constraint someday i'll be happy to use revel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants