Giter Club home page Giter Club logo

goradd's Introduction

Build Status

GoRADD

A rapid Web application development framework for Go.

GoRADD is a monolithic web development framework for rapidly creating a web application from a concept in your mind and then allowing you to as easily as possible maintain that application through all the twists and turns of the change process. It is ideal for prototyping, intranet websites, websites that are very data intensive with many forms to gather information from users, websites that require the security and speed of a compiled language, websites with thousands of simultaneous users, and websites being maintained by one or a small group of developers. It is particularly good for developers new to GO and/or new to web development.

Installation

See the Quick Start guide to get started.

Requirements

  • Go 1.21 or greater
  • A supported database up and running on your local development computer. Current supported databases are:
    • Mysql
    • Postgres

For Developing GoRADD itself

  • Sass (to build the css files from the scss source)

Goals

  1. 80-20 rule, where out of the box GoRADD will do most of the hard work of building a website, and will quickly get you a working website, but not necessarily one that you will want to ship. GoRADD is architected to allow you to make changes and plug in other open-source software as you need.
  2. Incremental changes. Most development processes go through a lengthy requirement analysis process, followed by a design process, and a lengthy build process, only to find out that what you built wasn't really what was needed. Instead, GoRADD gets you a working website quickly, and then lets you build out your application incrementally. It tries to make it easy to restructure your website, even at the data structure level, and have your changes filter through your application quickly without requiring a complete rewrite.
  3. Layered development. GoRADD has its code, you have your code, and then there is an in-between interface that changes over time. GoRADD uses code generation to create this interface, and clearly delineates the code that you can change to modify the interface, vs. code that it will generate as you change your data model. The result is a product that is easy to change as your world and requirements change.
  4. Most development happens in GO. What the user does in the browser is mirrored on the server, which allows you to work in a way that feels like you are building a desktop application. This makes your developers more productive and it allows you to build your app using common GO tools like the built-in unit test environment and documentation server. You can still work in javascript if you want to or need to do custom UI work, but often you don't have to.
  5. Stability. We want to build applications that real people use, and that means reliance on tried and true technologies that work on a broad range of browsers and servers, rather than technologies that require lots of Polyfills for emerging standards.
  6. Progressive enhancement. If you use the provided widgets, you can create a website that works even if the client turns off Javascript. All major browsers are currently supported, but we hope to support Opera Mini as well.
  7. Rich libraries of widgets. GoRADD provides standard widgets corresponding to basic html controls, and also provides Bootstrap widgets. If you have a particular css or javascript widget library you want to support, building the GoRADD interface is fairly easy to do, and the Bootstrap library included gives you a model to follow.
  8. Scalability. GoRADD is architected for scalability. All user state information is serializable to key-value stores. You might need to build the interface to the particular key-value store you are interested in, but that is not difficult. Some specific issues to consider:
    1. GoRADD requires a MySQL or Postgres database at this point for your main data store. SQL is great for creating most common data structures, is great when you need to change your structure without destroying data, and is fast enough for most applications. However, all data access is done through a common API, so switching an application that is already written to another SQL database like Postgres, Oracle, or any other database is very straight-forward and is just a matter of implementing the database layer.
    2. GoRADD maintains the state of each user of the website in something we call the pagestate. The pagestate is serializable to any key-value store. Currently, only an in-memory store is provided, but writing an interface to any common key-value store is easy.
    3. Live updates work through a pub/sub mechanism. Goradd provides a single-server in-memory system out of the box, but its easy to switch to any other pub/sub mechanism, including distributed systems like pubnub, ally, google cloud messaging, etc. There are no payloads with the messages and traffic is minimal.

Future Goals

  • Expand database drivers, including NoSQL support
  • WebComponents. WebComponent architecture fits particularly well with goradd's architecture. However, WebComponents are not fully supported by all major browsers. As WebComponents gain traction, we hope to use them for future browser widgets.
  • Automated generation of a REST Api, including generation of Flutter client code.

Anti-patterns

  1. GoRADD's html server is not microservice based. While you can create microservices that serve parts of your application, at its core goradd is a monolithic framework that includes an ORM, an MVC architecture, and a basic control and form management library. That said, GoRADD is still very scalable.
  2. Object-oriented. Some of goradd uses a code pattern that mirrors traditional object-oriented inheritance and gets around some of GO's limitations in this area, including implementing virtual functions. We have found this particularly useful in the control library. If you hate inheritance, goradd is not for you. If you don't mind it, but you still like object composition too, this is your place.
  3. Code generation. GoRADD relies heavily on code generation, and in particular uses the related github.com/goradd/got template engine to generate code.

Acknowledgements

GoRADD is a port of the PHP framework QCubed. QCubed itself was a fork of the PHP framework written by Mike Ho called QCodo. Mike is the original mastermind of many of the concepts in GoRADD, like:

  • A code-generated ORM
  • The use of "nodes" to describe database entities AND the relationships between them.
  • Code-generated CRUD forms to get you started.
  • Scaffolding that separates code-generated code from developer code so that code-generation can continue throughout the life of the project.
  • A lightweight javascript layer for processing events and actions through ajax.
  • The formstate engine to mirror the state of html and javascript widgets on the server-side so that the server-side engineer has complete control over what is happening in the html without needing to write javascript.

GoRADD relies on a number of other open-source projects, including:

GoRADD was created and is maintained by Shannon Pekary

Thanks To

JetBrains for use of the GoLand Go Editor

BrowserStack BrowserStack for automated browser testing tools

goradd's People

Contributors

sonashannon avatar spekary avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

goradd's Issues

Missing bug/model

I am starting off with goradd and followed the Quick Start guide

I have a import statement in web/login/login_form.go for "goradd-project/gen/bug/model" which is unresolved. How do I fix it?

I was using dep with go 1.12 the last time I made an app with golang and am new to the go modules. How do I resolve this?

Adding/removing controls with attached scripts

Deal with hiding and showing/adding & removing of child controls with attached scripts. Coordinates with auto-drawn controls, dialogs and proxies too. Must be able to remove and add the attached or related scripts (possibly? Removal may not be necessary, but replacement, yes)

Why not just a server!?

Hey @spekary

I think the shape is good but I also think that the industry is fast moving towards decoupling. Most apps do not render their own HTML a lot. They do the minimal stuff (just the case content) and then let JS do the work on the front end. Most sites that are going to be accompanied by an app these days and thus, they require the APIs and front-end to stay separated. Is there something you are working on towards that?

Webconnect and watcher support

Webconnect is mostly implemented. Needs to be tied in to a watcher, which will require some kind of key-value database implementation. Should potentially implement the ability to query what other users are online.

Handle date/time display

The strategy will be to have special widgets that will receive date/time combinations in UTC, and then have javascript convert to a local timezone and display. We will need both a SPAN type object, and a column for tables. We will need equivalent versions, or options, to do no conversion and instead represent a local time in whatever the current time zone is.

We will need options for short and long dates and times, time only or date only, etc.

JS:
new Intl.DateTimeFormat(navigator.language, { dateStyle: 'short', timeStyle: 'short'}).format(date)
Leaving off dateStyle makes a time-only output. Similarly, leaving off timeStyle is date-only.

A Date/Time field would need to populate it this way, but also parse it too in javascript.

Date, Time and Date/Time pickers

Since some browsers support date, time and datetime-local input types, perhaps the best thing here would be to simply allow these to be set as inputs, and then simply validate the human input. The validators could be used for other widgets to make it easier to implement other javascript date and time pickers.

Improve drawing code

Look again at the problem of constantly switching between drawing into a buffer and drawing into a string. This is also related to the fact that we build up tags by constantly wrapping them. Perhaps we can more efficiently do this by using buffers that are allocated at the beginning and end of the buffer, and then we draw in the middle, gradually adding to the beginning and end as we wrap and grow. We can look at the buffer implementation for hints.

Another possibility is to draw into a byte array rather than strings, since a byte array will not create allocations when it is passed between functions.

Prevent Name Collisions in ORM

It is possible to have a variety of name collisions that we should check for. #42 is an example, but another one is if a many-many or reverse-reference uses the same name as a different colmn in the table.

Use EventSource instead of WebSocket for updates

Since we are only using WebSocket to deliver an update notification to the browser, we can use an EventSource instead. It has some advantages with regards to getting through proxies and is easier for load balancers, but it has some difficulties too:

Edge and IE browsers do not support this, but there is a polyfill available for just these two.

Serialization improvement

Serialization has some potential improvments:

  1. We can store pointers to controls in other controls by implementing a scheme where we control how the controlRegistry is serialized, going bottom-up the hierarchy. Pointers to controls will then be serialized only as a controlID. Then, when we deserialize, we can know that those controls are available in the controlRegistry during the deseralization process.

  2. We should detect that a control has the Serialize function, and not call it if its present. This is a little difficult using reflect, as the Method list returns all the methods, including methods from anonymous embedded structures. It may be possible to detect be looking at the Type->Method->Pkg structure and comparing to the package of the struct itself to see if they are in the same place.

Invalid memory address or nil pointer reference

I am getting this error page when trying to access the tutorial's "Code-generated objects" page:

Screenshot 2020-11-23 at 1 35 50 PM

Full Call path is this:

/usr/local/Cellar/go/1.15.2/libexec/src/runtime/panic.go line 212 in runtime.panicmem
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/signal_unix.go line 720 in runtime.sigpanic
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/examples/gen/goradd/model/Person.base.go line 437 in github.com/goradd/goradd/web/examples/gen/goradd/model.newPersonBuilder
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/examples/gen/goradd/model/Person.go line 49 in github.com/goradd/goradd/web/examples/gen/goradd/model.queryPeople
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/examples/gen/goradd/model/Person.base.go line 404 in github.com/goradd/goradd/web/examples/gen/goradd/model.LoadPerson
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/examples/tutorial/orm/1-objects.tpl.go line 41 in github.com/goradd/goradd/web/examples/tutorial/orm.(*ObjectsPanel).DrawTemplate
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 594 in github.com/goradd/goradd/pkg/page.(*ControlBase).DrawInnerHtml
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 544 in github.com/goradd/goradd/pkg/page.(*ControlBase).DrawTag
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 437 in github.com/goradd/goradd/pkg/page.(*ControlBase).Draw
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 616 in github.com/goradd/goradd/pkg/page.(*ControlBase).DrawChildren
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 603 in github.com/goradd/goradd/pkg/page.(*ControlBase).DrawInnerHtml
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 544 in github.com/goradd/goradd/pkg/page.(*ControlBase).DrawTag
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/control_base.go line 437 in github.com/goradd/goradd/pkg/page.(*ControlBase).Draw
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/examples/tutorial/index.tpl.go line 104 in github.com/goradd/goradd/web/examples/tutorial.(*IndexForm).DrawTemplate
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/form_base.go line 152 in github.com/goradd/goradd/pkg/page.(*FormBase).Draw
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/page_template.tpl.go line 33 in github.com/goradd/goradd/pkg/page.PageTmpl
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/page.go line 167 in github.com/goradd/goradd/pkg/page.(*Page).Draw
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/page.go line 146 in github.com/goradd/goradd/pkg/page.(*Page).runPage
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/page/page_manager.go line 158 in github.com/goradd/goradd/pkg/page.(*PageManager).RunPage
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 238 in github.com/goradd/goradd/web/app.(*Application).ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 348 in github.com/goradd/goradd/web/app.(*Application).ServeAppHandler.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 363 in github.com/goradd/goradd/web/app.(*Application).PutContextHandler.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/pkg/session/scs.go line 49 in github.com/goradd/goradd/pkg/session.ScsManager.Use.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 318 in github.com/goradd/goradd/web/app.(*Application).HSTSHandler.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 396 in github.com/goradd/goradd/web/app.(*Application).BufferedOutputHandler.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/Users/vkaushal288/go/pkg/mod/github.com/goradd/[email protected]/web/app/app_base.go line 527 in github.com/goradd/goradd/web/app.(*Application).AccessLogHandler.func1
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2042 in net/http.HandlerFunc.ServeHTTP
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2417 in net/http.(*ServeMux).ServeHTTP
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 2843 in net/http.serverHandler.ServeHTTP
/usr/local/Cellar/go/1.15.2/libexec/src/net/http/server.go line 1925 in net/http.(*conn).serve
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/asm_amd64.s line 1374 in runtime.goexit 

Pagestate counter

There is a potential problem with the pagestate. Some browsers let you duplicate a page, and so the pagestate will also be duplicated. Then we will have two pages with the same pagestate, and that could cause a collision. We need to implement an ajax counter along with the pagestate that will make sure each hit to the server is sequential. If we get something out of order, we know that there are two pages with the same pagestate. In that situation, we can just force one of the pages to reload, and so it will get a new pagestate, and there will no longer be a collision.

Webcomponent like architecture for controls

Way in the future, but instead of drawing a whole control's html, a control could instead be a combination of an html declaritive tag like a WebComponent, and a template that draws it. It could be an actual Polymer component, or something similar. This way, all templates get sent to the browser one time, and then they are called on through declarative statements or javascript calls.

Verify Opera Mini support

Opera Mobile is surprisingly common in African countries. Make sure its supported by javascript library.

Auto-complete widget

Reimplement an auto-complete like widget that is mobile friendly.

  • Filtered single or multi-picker list
  • Option to add a new one if the filter does not exist
  • Autofill?
  • Tag creator/picker
  • Source of data should be uploaded and synchronized. Ajax data source can be problematic because of delays, and such a thing is really only necessary when dealing with a very large data set, in which case an autofill picker that you can add an item really has to deal with things differently, even purposefully delaying and putting up a dialog to ask to create a new value. The big problem comes when we are waiting for an ajax response and the user decides to save a form before the response comes back, or simply tab out before the response comes back. The response may not ever come back, so probably need to use validation to prevent the submission of the form.

Implement widgets that are linked to javascript data store

Some widgets benefit from getting their data from a javascript datastore, and when data changes on the server, you update the datastore. In particular, scrolling widgets have their scroll location reset when the whole widget is drawn, and doing it with a linked datastore allows for it not to do that.

Unit test framework for controls

This will need ways to do code coverage directly accessing the control using the traditional Go testing framework, and also using the web driver

Validate keys are labeled auto-increment

Must make sure keys are also labeled auto-increment so that they will be treated as strings, in particular for type tables. This should be a warning generated during codegen if this is not true.

[ Question ] SPA

A couple of years ago with QCube for a bunch of projects. Since then, I never found anything that had a speed closer to it in terms of development. I think you were a big contributor to QCube and I recently discovered this repo and that QCubed is mostly dying.

These days, I'm mostly a full-stack dev. I work with backends build on nodejs with frontends done in react.

My question here is: When you started this project, did you thought about doing it with an API and a frontend? I mean, all the code generation would still be here for the front and back, but the backend and frontend would be split in two and you would have a modern SPA with a API on the back.

This would allow you to generate only the front or backend if necessary, plug other stuff to the api (example: mobile apps), have a frontend easy work it and with the possibility to had a huge amount of pre-existing modules from npm (for this I speak mostly for react and vue), and more that I won't list here because it's not important for the discussion.

Implement Gijgo controls

In particular, the date, time and date-time pickers look interesting. We might make Gijgo core. But it requires jquery, so maybe not.

Add timestamp version of DateTime fields

Some databases do not have timestamps, like SQL lite. We can use database comments to specify that a field is timestamped even if it does not have official support from the database maker. This would involve making sure that datetimes are saved in UTC. Would also need to add a variety of tests.

Page serialization

This is partly complete. Waiting for the testing framework for controls so that once we implement serialization, we can test it using control unit tests. This is done enough so that the architecture is in place.

This feature is not needed for single-server deployments.

Join js and css files

Implement processes to join javascript and css files into one file, but have the various references to the original files point to the joined files in release builds.

Remove JQuery dependency

This is not easy, and not sure its really important. jQuery is not very big, and is really useful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.