The rise of JavaScript applications is tremendous. Every week new JS frameworks appear. Every website UI is now JS-heavy.
How can Rails react to it?
Do we need to worry about our jobs?
History
Let's go back to the history for a while.
Rails was created as a light-weight, but well-structured alternative to create dynamic, db-backed, html websites.
I still own the main Rails book, that was published in 2005: Agile Web Development with Rails. I just checked, there was 558 pages of good content. Only 16 pages were about The Web, V2.0 (this part was written by Thomas Fuchs, not by the main authors - DHH and Dave Thomas). Back then, Rails supported JS via the prototype library. There was no mention about RJS, yet.
Late 2006, I bought another book - Ajax on Rails. I have it in front of me right now. This time, RJS was important already, as they wrote: "Ruby-generated JavaScript (RJS) is the capstone of Ajax in Rails". Before the concept was introduced in the book, all the server did was returning HTML snippets (data) and the JS libraries inserted it into appropriate places. No such thing as view model, data-binding, etc, yet.
Where are we now?
Rails does a really good job of handling the backend part. It's secure, based on conventions, all apps are similar, everybody knows how to work with it.
Look at the frontend part of many Rails apps, though - you don't see the conventions, you don't see the same structure everywhere.
There's this pro-Rails argument, that it's better for a startup to do Rails, because many Rails devs will know what is going on if the project is done the-Rails-way - so, it's easier to scale the team. It's no longer true, though. Yes, the backend part is usually familiar, but the JavaScripts? They're completely different in every Rails app. Often, they're like 50% of the codebase.
Some developers just hack together some jQuery plugins and call it a day.
Some developers go with DHH suggestions and use RJS (UPDATE: or clean JS returned from the server) (to be honest I have never seen this approach in a Rails app, but I'm sure someone followed DHH here).
The new trend is to use JS frameworks, like Ember.js or Angular.js, which are opinionated and feel more aligned to the philosophy of Rails (conventions, magic, implicit features).
Other developers (me included) want to control the JavaScript app and don't use any framework, relying on self-imposed architectures like http://hexagonaljs.com/.
How can Rails react?
There are some possible ways of reacting. I'm trying to be neutral here, although obviously I have an opinion on that.
1. We can leave it as it is, with [R]JS being recommended by the leader
From my observations, the [R]JS recommendation gets ignored mostly. To be fair, none of the leaders is actively discouraging anyone to use some proper JS frameworks. It's just not the main focus.
This leaves the community disconnected from the leader (which may not be a bad thing). I've met many people who are worried for the future of Rails. They're not sure if Rails is a good technology to invest their time. For such people it may mean that in the longer run, they'll prefer to focus their education on the JS part more than on the Rails. We already see the increasing number of jobs ads requiring Angular or Ember.
This way, we'll see the trend started with rails-api growing in popularity.
2. Rails can adopt/recommend one of the JS frameworks.
It can be Angular or Ember. The first one has a huge growing trend recently. Ember is led by well-respected people from the Rails community (Yehuda). It's smaller overall but quite popular in the Rails world already.
We've seen a similar situation in the history of Rails, when Yehuda created Merb and then made it to Rails (oversimplifying a bit). Can the same happen with Ember? It's very likely.
What about Angular which is becoming the default JS framework? Can Rails recommend it? There's nothing in Rails that makes it hard to develop with Angular. But Angular is not the default choice, yet. DHH made some bold moves in the past, like making CoffeeScript on by default (thank you!). Can the same happen to Angular?
3. Rails will encourage JS frameworks but stays JS-framework-agnostic.
This is more or less what is happening already in the community. People use Rails together with many of the existing JS frameworks, with success.
4. All of the above
We can see DHH keep recommending [R]JS. The Rails core will make Ember the default choice, but easy to disable it. The community will keep using Rails together with everything.
The future
What is going to happen? I honestly don't know. Rails is doing fine-enough. It doesn't need to react in any way. We need to remember that it's not only about purely rational, technological choice. Rails was always famous for its marketing. We can see some unexpected moves, like coming up with its own JS framework.
What would I prefer?
Personally, the current situation is fine for me. I ignore the [R]JS way of creating the Rails apps. I'm allowed to create the JavaScript apps the way I want. Rails is good for API. I'm fine with any choice.
However, as I said, it's not only about rational choices, it's about the emotions. Do we want it or not, the Rails community is huge nowadays with new people coming every day.
If my main goal was to keep Rails hot for the new people, then I'd suggest choosing Angular as the framework that is on by default in Rails. That would bring a lot of love to the community. Angular is loved they way Rails used to be loved. I personally don't really like the Angular way, but this choice will be good/easy for the new people for whom it's better to follow choices made by others.
In the meantime, other backend communities keep improving. Did you see PHP and Symphony2? It's a framework which is architecturally ahead of Rails (a topic for another blog post, probably). Did you notice how popular Scala is becoming?
Should we care about the future of Rails? Is it more pragmatic to be backend-independent and start learning more about other backend choices? Should we go the microservices way and have the app implemented in several backend technologies at the same time?
Many questions, lots of guessing :)
If you liked this blog post, you will enjoy following me on Twitter.
UPDATE: I changed RJS to [R]JS in some places. It's not really RJS that is recommended by DHH, but SJR - Server JavaScript Responses - see http://37signals.com/svn/posts/3697-server-generated-javascript-responses
Saturday, December 28, 2013
Sunday, December 22, 2013
Decentralise id generation
It seems to be a common practice nowadays to rely on the database-generated, incremental id.
In one of our projects, we let the client-side (JS) generate the id (using guid/uuid). It leads to interesting consequences. We no longer need to send the form data to the backend immediately. If we want, we can create the object on the client-side, give it a guid, keep editing it and then send it back to the server, with the guid. The server stores the guid and uses it for identification. The same can happen at the same time from another Ruby client that connects to the same API.
This is how an example guid looks like:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
"A UUID is 128 bits long, and can guarantee uniqueness across space and time."
RFC: http://www.rfc-archive.org/getrfc.php?rfc=4122
"A UUID is an identifier that is unique across both space and time, with respect to the space of all UUIDs. Since a UUID is a fixed size and contains a time field, it is possible for values to rollover (around A.D. 3400, depending on the specific algorithm used)."
In one of our projects, we let the client-side (JS) generate the id (using guid/uuid). It leads to interesting consequences. We no longer need to send the form data to the backend immediately. If we want, we can create the object on the client-side, give it a guid, keep editing it and then send it back to the server, with the guid. The server stores the guid and uses it for identification. The same can happen at the same time from another Ruby client that connects to the same API.
This is how an example guid looks like:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
"A UUID is 128 bits long, and can guarantee uniqueness across space and time."
RFC: http://www.rfc-archive.org/getrfc.php?rfc=4122
"A UUID is an identifier that is unique across both space and time, with respect to the space of all UUIDs. Since a UUID is a fixed size and contains a time field, it is possible for values to rollover (around A.D. 3400, depending on the specific algorithm used)."
"Unless you're accepting IDs on, say, an Internet-wide scale, or with an untrusted environment where malicious individuals might be able to do something bad in the case of an ID collision, it's just not something you should worry about."
My opinion on UUIDs
For years, I have been thinking that centralised id generation is the natural way. Seems obvious. After I learnt mote about UUID, I start seeing more and more good things about it. It allows for less coupling between components/services. You no longer need to 'ask' for the id. In case of JavaScript frontends it solves the problem of whether to block the UI, when we create a new resource.
The area, that I haven't researched much is having distributed database which you sync between the services. From what I know, it's already possible with http://www.datomic.com/.
Ruby
Ruby has a built-in method:
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/rdoc/SecureRandom.html#method-c-uuid
p SecureRandom.uuid
# "2d931510-d99f-494a-8c67-87feb05e1594”
JavaScript
JS library
https://github.com/pnegri/uuid-js
var uuid4 = UUID.create();
console.log(uuid4.toString());
// Prints: 896b677f-fb14-11e0-b14d-d11ca798dbac
Python
>>> import uuid
>>> # make a UUID based on the host ID and current time
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e’)
Java
UUID uuid = UUID.randomUUID();
Also worth reading: http://stackoverflow.com/questions/703035/when-are-you-truly-forced-to-use-uuid-as-part-of-the-design/786541#786541
My opinion on UUIDs
For years, I have been thinking that centralised id generation is the natural way. Seems obvious. After I learnt mote about UUID, I start seeing more and more good things about it. It allows for less coupling between components/services. You no longer need to 'ask' for the id. In case of JavaScript frontends it solves the problem of whether to block the UI, when we create a new resource.
The area, that I haven't researched much is having distributed database which you sync between the services. From what I know, it's already possible with http://www.datomic.com/.
Ruby
Ruby has a built-in method:
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/rdoc/SecureRandom.html#method-c-uuid
p SecureRandom.uuid
# "2d931510-d99f-494a-8c67-87feb05e1594”
JavaScript
JS library
https://github.com/pnegri/uuid-js
var uuid4 = UUID.create();
console.log(uuid4.toString());
// Prints: 896b677f-fb14-11e0-b14d-d11ca798dbac
Python
>>> import uuid
>>> # make a UUID based on the host ID and current time
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e’)
Java
UUID uuid = UUID.randomUUID();
Also worth reading: http://stackoverflow.com/questions/703035/when-are-you-truly-forced-to-use-uuid-as-part-of-the-design/786541#786541
Saturday, December 21, 2013
The Four Architectures that will inspire your programming
This is the Big 4. The architectures, that may help your work. They may influence the way you think about programming.
1. The Hexagonal Architecture
(also known as the Ports and Adapters)
Originally described by Alistair Cockburn in http://alistair.cockburn.us/Hexagonal+architecture.
Enhanced and popularised by Steve Freeman and Nat Pryce, thanks to their book: http://www.growing-object-oriented-software.com/
2. Clean Architecture
Originally described by Ivar Jacobson, but popularised by Uncle Bob: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
3. DDD/CQRS
DDD: Domain-Driven Design
CQRS: Command Query Responsibility Segregation
Two separate concepts, but together create quite a unique architecture.
DDD is originally invented by Eric Evans. CQRS is often popularised by the work of Greg Young.
4. DCI
DCI: Data Context Interaction
James Coplien, Trygve Reenskaug
Desribed in James' book: http://www.leansoftwarearchitecture.com/ and here: http://www.artima.com/articles/dci_vision.html
What I think about them
I don't treat them as competitors. Learning the concepts behind them (still in progress) inspired me to bring some new ideas to our projects. Usually, they're not all or nothing.
The most mind-blowing architecture is definitely DCI. This is the future of programming. The vision of objects being different things in different contexts, while still keeping its identity is fantastic. Unfortunately, DCI is also the hardest one to use in day-to-day practice. Some of the concepts required (objects with roles) are hard to achieve in most popular languages.
The most practical architecture is possibly DDD/CQRS. There is a lot of example projects in many different languages. I love the pragmatic approach of splitting the system into Commands and Queries. At first, I couldn't get the point, but after more reading I see the beauty of it. I sometimes laugh that DDD could stand for (data) Duplication-Driven Design. It opened my eyes to the idea, that we can have multiple subsystems, each with its own storage. Some data will be duplicated this way, but it's often not a problem. The data is eventually consistent.
Another nice thing about DDD is the idea of Bounded Contexts. It's a terrible name, but a really useful concept of a module that encapsulates one little world of your project. Usually, you have one root object in each Bounded Context, which is called Aggregate. The same 'object' can exist in different BC, but will have a different name. Its identity will be kept via a unique id.
CQRS brings the concept of Commands being the most complex parts of your app, while Queries are usually very simple and don't require many layers.
What I like about the Clean Architecture is its focus on clear dependencies and on boundaries. Boundaries should be kept outside of your application. The communication between boundaries should happen via Data Transfer Objects. In the middle there's the Interactor, which represent a UseCase.
Last, but not least, we've got the Hexagonal Architecture. This is what inspired us mostly to create the JavaScript non-framework called http://hexagonaljs.com/. It's so easy to extract GuiAdapter and StorageAdapter, leaving the middle hex boundary-unaware.
HexagonalJS is a result of inspiration from all of the above architectures. We took the UseCase/Context part from the DCI architecture with a little bit of the Clean Architecture. The idea of adapters is taken from the Hexagonal Architecture. The middle hex is often implemented using the building blocks taken from DDD. Our unique addition to this setup is a little bit of Aspect Oriented Programming.
Often, when I'm in doubt how to approach a new project, I'm trying to stand far from the Upfront Design. However, it doesn't hurt if I imagine the project in each of the architectures. This gives me new ideas about the domain I'm implementing.
If you liked this blog post, you will enjoy following me on Twitter.
1. The Hexagonal Architecture
(also known as the Ports and Adapters)
Originally described by Alistair Cockburn in http://alistair.cockburn.us/Hexagonal+architecture.
Enhanced and popularised by Steve Freeman and Nat Pryce, thanks to their book: http://www.growing-object-oriented-software.com/
2. Clean Architecture
Originally described by Ivar Jacobson, but popularised by Uncle Bob: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
3. DDD/CQRS
DDD: Domain-Driven Design
CQRS: Command Query Responsibility Segregation
Two separate concepts, but together create quite a unique architecture.
DDD is originally invented by Eric Evans. CQRS is often popularised by the work of Greg Young.
4. DCI
DCI: Data Context Interaction
James Coplien, Trygve Reenskaug
Desribed in James' book: http://www.leansoftwarearchitecture.com/ and here: http://www.artima.com/articles/dci_vision.html
What I think about them
I don't treat them as competitors. Learning the concepts behind them (still in progress) inspired me to bring some new ideas to our projects. Usually, they're not all or nothing.
The most mind-blowing architecture is definitely DCI. This is the future of programming. The vision of objects being different things in different contexts, while still keeping its identity is fantastic. Unfortunately, DCI is also the hardest one to use in day-to-day practice. Some of the concepts required (objects with roles) are hard to achieve in most popular languages.
The most practical architecture is possibly DDD/CQRS. There is a lot of example projects in many different languages. I love the pragmatic approach of splitting the system into Commands and Queries. At first, I couldn't get the point, but after more reading I see the beauty of it. I sometimes laugh that DDD could stand for (data) Duplication-Driven Design. It opened my eyes to the idea, that we can have multiple subsystems, each with its own storage. Some data will be duplicated this way, but it's often not a problem. The data is eventually consistent.
Another nice thing about DDD is the idea of Bounded Contexts. It's a terrible name, but a really useful concept of a module that encapsulates one little world of your project. Usually, you have one root object in each Bounded Context, which is called Aggregate. The same 'object' can exist in different BC, but will have a different name. Its identity will be kept via a unique id.
CQRS brings the concept of Commands being the most complex parts of your app, while Queries are usually very simple and don't require many layers.
What I like about the Clean Architecture is its focus on clear dependencies and on boundaries. Boundaries should be kept outside of your application. The communication between boundaries should happen via Data Transfer Objects. In the middle there's the Interactor, which represent a UseCase.
Last, but not least, we've got the Hexagonal Architecture. This is what inspired us mostly to create the JavaScript non-framework called http://hexagonaljs.com/. It's so easy to extract GuiAdapter and StorageAdapter, leaving the middle hex boundary-unaware.
HexagonalJS is a result of inspiration from all of the above architectures. We took the UseCase/Context part from the DCI architecture with a little bit of the Clean Architecture. The idea of adapters is taken from the Hexagonal Architecture. The middle hex is often implemented using the building blocks taken from DDD. Our unique addition to this setup is a little bit of Aspect Oriented Programming.
Often, when I'm in doubt how to approach a new project, I'm trying to stand far from the Upfront Design. However, it doesn't hurt if I imagine the project in each of the architectures. This gives me new ideas about the domain I'm implementing.
If you liked this blog post, you will enjoy following me on Twitter.
Friday, December 20, 2013
Turn a Rails controller into a Single Page Application
Single Page Apps are becoming more popular. When you see them in practice (GMail, Twitter, Facebook), it's quite cool. Then you look at your current project and you see how impossible it is to make it a Single Page App. Who's going to pay for that? It sounds like months of work, just replacing the whole existing functionality.
The thing is, it doesn't need to be the whole project at once. It's not all or nothing. You can make multiple small SPAs.
Where to start?
Look at your current Rails views/controller. Is there a clear widget, like a search bar, that could be extracted? That's a good candidate.
There's also another approach. Usually when you have a typical CRUD controller, it's always the same group of views. There's a list of things, that you can see, edit, update, add new items, etc.
Such controller is a good candidate for a SPA.
You end up with one view (index), which loads the JS. After the JavaScripts are initialised, an AJAX GET request is made to /index.json. This retrieves all the data for the list. Apart from that you need an API endpoint for creating, updating and deleting. Note that you don't need an endpoint for new/edit. They become JavaScript views, but they don't need to exist on the server-side.
You turn the existing Rails views into handlebars templates (or whatever that renders the HTML client-side). They get rendered at appropriate moments by the JavaScript code.
If you prefer, you can use a framework for that. You can also do it on your own, as it's very easy. We usually go the hexagonaljs way - manual, with a nice structure and typical adapters: serverSide and guiAdapter.
What does it give you?
- Single Page Apps are architecturally better solutions than Rails views
- it's easier to test
- once you learn it, it's quite easy to write
- there's strong decoupling between your frontend and the backend
- the backend is simpler
- the resulting SPA has less 'features' than a Rails view
- by default, no URL for each 'view', just for the main one
- good enough for most cases
- for SEO you need to do additional work on the backend
- not always needed
It doesn't need to be all or nothing
You can test the water by choosing some parts of your project and turn them into JavaScript apps. We're in the process of doing that in a large Rails project - I think, we're now with about 15 small Single Page Apps. We keep adding new features, it doesn't slow us down. Thanks to the faster build (it's easier to test decoupled components rather than a monolith), we're actually saving time.
Tuesday, October 8, 2013
The Rails-way and bigger projects
The whole idea of having a data-structure that you retrieve from the database and carry through all the layers to the UI makes the development very quick at the beginning.
The coupling it provides, at the later stages of development makes it very difficult to split the app into any kind of modules. It's also difficult to test anything in isolation. That's why Cucumber, Capybara, Selenium are so popular, as they help you in writing integrated tests.
Integrated tests have their place, but it's impossible to test everything through all the layers. This results in slow builds - a typical syndrome in Rails projects.
The Rails way makes sense for smaller projects. What I'm disagreeing with is using "The Rails way" in bigger, serious projects.
The Rails itself has nothing inherently wrong. I'm not attacking Rails, I'm only attacking 'the Rails way'. You can use Rails for bigger projects, if you know what you're doing.
What I'm teaching at my Rails class
It's now the 4th time, I'm teaching the Rails class at the University of Wroclaw. The main goal of this class to prepare people to work in a Rails-based company. The students are the best of the best, so the goals can be high.
Every year, I introduce some changes to the program of teaching to reflect better what is happening in the Rails community.
This year I'm going to focus more than before on the integration with mobile, native apps and on the art of dealing with legacy projects.
We start with extremely quick Ruby lessons, based on the Ruby koans exercises (students do it on their own).
The first 3 lessons are about "the Rails way", which I make it clear - is good only for toy projects. This is where I teach about ActiveRecord-oriented programming, coupling everything with everything, making things impossible to test - you know, the usual Rails stuff.
Once we know the enemy and know the pains it provides, we learn how to avoid that.
This is where good, solid OOP lessons come in, service objects, repositories, domain objects, etc.
After that, we enter the "frontend" module. We learn how to create Single Page Apps using the dominant JS frameworks (Angular) and some no-framework techniques (HexagonalJS. This also includes techniques like Pusher to have server->client communication possible.
We also talk a lot about the way, a Rails backend can expose data through the API to the JS or mobile app clients. Mobile apps will take more time this way, as I want to show how to best cooperate with mobile developers.
There's a lesson about proper Rails deployment, things like Chef, Jenkins, Continuous Deployment etc.
Throughout the class, we'll not only create new Rails apps (lots of them), but I also want to teach how to find yourself in a legacy codebases, like Redmine or Discourse, how to refactor out from the mess, fix bugs, add new features - that's probably the hardest part of the class.
Testing is an ongoing topic in the class, as well. We'll learn about unit testing of different layers, integrated tests and their pains.
I hope it will be fun, as always :)
Every year, I introduce some changes to the program of teaching to reflect better what is happening in the Rails community.
This year I'm going to focus more than before on the integration with mobile, native apps and on the art of dealing with legacy projects.
We start with extremely quick Ruby lessons, based on the Ruby koans exercises (students do it on their own).
The first 3 lessons are about "the Rails way", which I make it clear - is good only for toy projects. This is where I teach about ActiveRecord-oriented programming, coupling everything with everything, making things impossible to test - you know, the usual Rails stuff.
Once we know the enemy and know the pains it provides, we learn how to avoid that.
This is where good, solid OOP lessons come in, service objects, repositories, domain objects, etc.
After that, we enter the "frontend" module. We learn how to create Single Page Apps using the dominant JS frameworks (Angular) and some no-framework techniques (HexagonalJS. This also includes techniques like Pusher to have server->client communication possible.
We also talk a lot about the way, a Rails backend can expose data through the API to the JS or mobile app clients. Mobile apps will take more time this way, as I want to show how to best cooperate with mobile developers.
There's a lesson about proper Rails deployment, things like Chef, Jenkins, Continuous Deployment etc.
Throughout the class, we'll not only create new Rails apps (lots of them), but I also want to teach how to find yourself in a legacy codebases, like Redmine or Discourse, how to refactor out from the mess, fix bugs, add new features - that's probably the hardest part of the class.
Testing is an ongoing topic in the class, as well. We'll learn about unit testing of different layers, integrated tests and their pains.
I hope it will be fun, as always :)
Monday, July 8, 2013
Implicit Rails features
This post is part of a series of blog posts. So far, there were 2 blog posts, which aim at helping you improve the modularity your Rails applications:
3. Implicit Rails features
The speed with which you start every new Rails application is amazing.
Within a few days you can have a fully working prototype of almost every application. Obviously, the prototype, by definition, may not be fully ready to production use.
With a really small codebase, the prototype does a lot of things. It's all thanks to many built-in Rails features.
I call them implicit features. They come almost for free.
- CRUD
- validations
- maintaining created_at and updated_at
- displaying errors
- displaying flash messages
- redirects between pages
- pagination
- uploads
- sending emails
- attr_accessible/attr_protected (security)
- CSRF - security
There's one downside to the implicit features.
They're rarely documented and covered with tests.
As with every app, there comes a moment, when you need to start providing changes. Sometimes, you may want to rewrite some layers of the application. There's a trend recently that we try to find new ways of working with Rails apps, that is less dependent on ActiveRecord. Some developers rewrite their apps to Sinatra or Padrino.
It sounds great in theory, but it's harder in practice.
It's good to be aware of such hidden functionalities. At some point, they can become explicit features, with their own tests, so that it's never broken.
If you know more such features, share them in the comments.
Sunday, June 23, 2013
ActiveRecord overdose
In the previous post, I highlighted the typical Rails bugs, that I encountered during my research on better ways of working on Rails apps. The bugs were often security-related:
The main common point of the bugs is the ActiveRecord overdose.
ActiveRecord overdose is a surprisingly popular pattern that includes:
The Rails-way ActiveRecord is an enhanced version of the original Active Record pattern. The original pattern assumed only persistence and some simple business logic. The Rails version extended it with the view/form responsibilities. In many cases it's also extended with the adapters.
The core responsibility of an ActiveRecord model is being a representation of a db record. That means handling the persistence and having the basic logic. This usually works great in typical CRUD apps. Once things get more complex, it's time to reconsider the active record pattern.
The main common point of the bugs is the ActiveRecord overdose.
ActiveRecord overdose is a surprisingly popular pattern that includes:
- putting everything into the model class
- fear of adding new non-AR classes
- over-relying on convention over configuration
- persistence
- business logic
- adapters
- view object
- form object
- others
The Rails-way ActiveRecord is an enhanced version of the original Active Record pattern. The original pattern assumed only persistence and some simple business logic. The Rails version extended it with the view/form responsibilities. In many cases it's also extended with the adapters.
- persistence
- associations
- queries - scopes
- saves
- simple validations
- business logic
- state-machine
- calculations
- tracking changes (touch)
- complex validations
- some callbacks
- feed/timeline/activity
- factories methods (class methods)
- adapters
- service (coordinating multiple adapters)
- search
- external api
- exception tracker
- metrics tracker
- image storage
- mailer
- notification
- view object
- first_name + last_name
- foo.to_s
- image_path
- http boundary details (urls)
- i18n
- form object
- accepts_nested_attributes_for
- sanitizing
- attr_accessor
- others
- acts_as_foo (persistence, logic, validations)
- concerns
- includes
The core responsibility of an ActiveRecord model is being a representation of a db record. That means handling the persistence and having the basic logic. This usually works great in typical CRUD apps. Once things get more complex, it's time to reconsider the active record pattern.
The best way of escaping from the ActiveRecord overdose is to do it step by step. I'll focus on that in my later posts.
Monday, June 17, 2013
Typical Rails bugs
As part of my research on improving Rails application, I noticed a pattern in the bugs that are quite characteristic to Rails in several applications.
They have certain 'visible' things in common:
Let's start with Discourse:
Fix wrong discount calculation with flat percent promotions when there are more than one line item in the order.
This error happened because the order instance here:
https://github.com/spree/spree/blob/master/core/app/models/spree/order_updater.rb#L24
is not always the same instance in memory here:
https://github.com/spree/spree/blob/master/core/app/models/spree/calculator/flat_percent_item_total.rb#L15
Adding the inverse option to the relationship makes sure you have the same object instance in both places.
When kaminary determines the total count of records it runs the following code
@collection.except(:offset, :limit, :order).count
The issue is that this sequence loads entire dataset to determine the count. This makes heavy load when products have large number of items.
The reason of this behaviour is group_by_products_id here https://github.com/spree/spree/blob/1-2-stable/core/app/controllers/spree/admin/products_controller.rb#L94
They have certain 'visible' things in common:
- often security related, like leaking some information to unauthorized users
- they live somewhere in the area of business logic/persistence
- they are not so easy to fix in the existing codebase
- they tend to exist in groups, similar bugs in different areas
- they are easy to miss
- often they appear during the requirements changes
Overdose of ActiveRecord
The reasons they exist is a combination of different things. The main common point of the bugs is the over-usage of ActiveRecord. It's easy to fall into this problem, I did it many times, as well.
You start with a new Rails app, adding new features very quickly. New requirements pop up. You use the popular Rails techniques to deal with them:
- validations, which often turn into conditional validations
- Single Table Inheritance
- state-machine
- accept_nested_attributes
- models callbacks
- virtual attributes
- external gems that provide value magically, by using ActiveRecord (implicit dependencies)
Every technique is fine on its own. When you start using all of them in the same area, problems appear.
Examples
I started noticing this trend, while reviewing the code of our potential Arkency customers. We sometimes do the "rescue missions" and help with legacy code. I can't use those examples here, so I started reviewing some of the popular open-source Rails applications: Discourse, Spree, Redmine, Gitlab. It didn't take me much time to discover the same bugs.
Just to be clear, all of the projects are awesome and I'm grateful to the people behind them. Most of the times, they deal with this kind of problems very quickly. I don't want to blame them for anything - they just serve here as examples.
Discourse
1. Digest mail ignores secure groups
People receiving the digest mail can easily read posts not meant for them. That's because the digest mail ignores the secure groups a member has access to or not.
Quite a problem as I unfortunately found out.
2. Non-authenticated users see private topics in 404 page
http://meta.discourse.org/t/non-authenticated-users-see-private-topics-in-404-page-was-mobile-view/7419
Discourse correctly prevented me from seeing the topic and instead showed a 404 page. On that 404 page, the lists of "Latest Topics" and "Recent Topics" showed private topics. I could click those links, which resulted in seeing the same 404 page again.
The 404 page should not show private topics.
3. Auto-suggest topics shows private topics
http://meta.discourse.org/t/auto-suggest-topics-shows-private-topics/7418/3
We've got Discourse running with private categories. When a user without access to the private categories type a new topic, they are presented with topics in categories to which they don't have access.
Comment: Did you notice the pattern here?
Accidentally, I've had a small conversation at HN with one of the Discourse founders. He said:
Those private topic bugs are not the result of ActiveRecord. We added a group layer on top of existing code and missed some places where queries did not respect it.
Had we used raw SQL instead of an ORM we would have had the same issues. All projects are open to this style of bug. The correct thing to do is report, close them quickly and add tests to prevent them from happening again (which we do.)
Quite a problem as I unfortunately found out.
2. Non-authenticated users see private topics in 404 page
http://meta.discourse.org/t/non-authenticated-users-see-private-topics-in-404-page-was-mobile-view/7419
The 404 page should not show private topics.
3. Auto-suggest topics shows private topics
http://meta.discourse.org/t/auto-suggest-topics-shows-private-topics/7418/3
We've got Discourse running with private categories. When a user without access to the private categories type a new topic, they are presented with topics in categories to which they don't have access.
Comment: Did you notice the pattern here?
Accidentally, I've had a small conversation at HN with one of the Discourse founders. He said:
Those private topic bugs are not the result of ActiveRecord. We added a group layer on top of existing code and missed some places where queries did not respect it.
Had we used raw SQL instead of an ORM we would have had the same issues. All projects are open to this style of bug. The correct thing to do is report, close them quickly and add tests to prevent them from happening again (which we do.)
I have completely no 'science' proof here, it's just based on my experience with hundreds of Rails projects. However, I disagree that all projects are open to this style of bug.
It's very typical to Rails projects.
The temptation of globally accessing every model/record from every place in the project makes it very easy to introduce such bugs. When you add new requirements (as they did) it's practically impossible to find all the places which should be changed.
Do I blame ActiveRecord here? No, ActiveRecord is a good library for persistence. It has its issues, it's huge, even the maintainers consider it a legacy code. Apart from some edge cases, it works more or less ok. I think the problem is relying on ActiveRecord for basically everything.
Spree
Let's see some other bugs, this time in Spree:
1. Fix wrong discount calculation with flat percent promotions
Fix wrong discount calculation with flat percent promotions when there are more than one line item in the order.
This error happened because the order instance here:
https://github.com/spree/spree/blob/master/core/app/models/spree/order_updater.rb#L24
is not always the same instance in memory here:
https://github.com/spree/spree/blob/master/core/app/models/spree/calculator/flat_percent_item_total.rb#L15
Adding the inverse option to the relationship makes sure you have the same object instance in both places.
Comment: Here we have another problem related to ActiveRecord. In more complex situations (cyclic associations), you can have the same 'record' in memory as two different instances, leading to errors.
2. Admin products loads entire dataset to determine the total count when paginating
When kaminary determines the total count of records it runs the following code
@collection.except(:offset, :limit, :order).count
The issue is that this sequence loads entire dataset to determine the count. This makes heavy load when products have large number of items.
The reason of this behaviour is group_by_products_id here https://github.com/spree/spree/blob/1-2-stable/core/app/controllers/spree/admin/products_controller.rb#L94
Comment: This time we have a combination of ActiveRecord and an external gem - kaminari (paginator). The end result is slowness of admin panels with thousands of products - they all will be loaded to memory. It's not the worst bug I've seen, but it's typical.
3. Default Tax Does Not Calculate Taxes Correctly if there is a Promotion
4. Taxes should be re-calculated after promotion adds an adjustment
Comment: the titles should be enough. This kind of bugs is usually related to the ActiveRecord callbacks usage. In complex scenarios it's not that easy to track all the places that need to be called after some changes.
Redmine
Let's now look at one Redmine bug:
1. Time entries of private issues are visible by users without permission to see them
Comment: Does it ring a bell? Again, a leak of private information.
Summary
We have seen some of the bugs, that I called typical Rails bugs. They seem to have certain things in common. I've seen them so many times, that they are the first things I look for, when I get access to a new project ticketing system.
Is there any way of defending against them? I think so. The best step to start with is to be aware of such problems. Try to spot them in your projects, see what history is behind the bug, spread the knowledge in your team.
In my next blog posts, I'll focus on techniques that should help decrease the number of such bugs. Stay tuned. In the meantime, you may want to follow me on Twitter and subscribe to the Rails Architectures Guide, that I'm working on.
Sunday, April 28, 2013
Single Page Applications fight - video
During the last wroc_love.rb conference we've organised a "fight" between 4 different approaches to Single Page Applications. Below is the video (0.5h) and a very short and simplified transcript from this event.
The participants, from the left-side:
Patrick Mulder - Backbone
Piotr Sarnacki - Ember
Andrzej Krzywda (me) - Hexagonal
Adam Pohorecki - Angular
moderator - Jan Filipowski
Andrzej: for all the apps
Adam: we need better tools on the backend in order to have a better developer experience
Piotr: Andrzej, would you write wikipedia as a SPA?
Andrzej: Yes.
Adam: What about SEO?
Andrzej: It's a myth that SPAs are not indexable. Google has an official document for that. It is additional work.
Patrick: You can use PhantomJS for SEO.
Adam: We've used PhantomJS for that, took a couple of hours.
8m28s
Patrick: Backbone, very small, minimal. you don't bring too much dependencies. you can choose what you want.
Adam: Angular, Two-way data binding is the key feature. Synchronization of HTML and your JS. Choose framework with data-binding. Ember is essentially a language, forces its own object model. Backbone as well. Hexagonal or Angular is pure JS.Your application can live outside of Angular.You could use Angular with a Hexagonal app. Backed by Google, more mature than Ember.
Andrzej: Data binding is not as important as you may think. Manual control is not that difficult. Hexagonal doesn't have data binding jilt-in. Apps are not about data changes, but about actions
Piotr: I agree that data binding is important. Both, Angular and Ember are good for big applications. Nested views, zombie views (backbone). Angular has its own compiler for DOM elements. You need to know how the compiler works. Angular uses dirty checking. Angular claims that your UI shouldn't have than 2000 elements. You're screwed if you have more.
Adam: We built a 100 rows, 500 columns table. We managed to do it with Angular. It's not that hard to do the UI part. Directives are like helpers for html.
Andrzej: It's a problem of all of us here, including Hexagonal. We use different terminology for different things. All the frameworks are far from being Rails, we're not mature enough. All the frameworks are in their infancy years.
Patrick: It's easy to work with Rails and Backbone
Piotr: Ember has its own class model. It's done mainly for making it easy to optimise. Ember is about Convention over Congifuration. Rails in JS. Ember is like Rails, Backbone is like Sinatra. At some point you have to use more plugins if you start with something minimal. A lot of pain if you want to write a big app with a small framework.
Andrzej: I disagree. I would use a framework for a prototype or for a small app. Once the app grows, it has its own world. I don't want the framework to go into my way. I want to have the control over the applications. I'd use Ember for smaller apps, not for bigger apps.
27m23s
Andrzej: Hexagonal has just started. It got the name just recently. We've used it for over a year. We have a strong team behind it. Our goal is to show the guidelines.
Piotr: Ember is 1.0RC now. Docs are better now. IRC is very active. Google Group.
Patrick: JavaScript and Ruby devs can help.
END
If you're interested in Single Page Apps, you may want to follow me on Twitter.
The participants, from the left-side:
Patrick Mulder - Backbone
Piotr Sarnacki - Ember
Andrzej Krzywda (me) - Hexagonal
Adam Pohorecki - Angular
moderator - Jan Filipowski
1m39s
Can anything be a Single Page App?
(and discussion about SEO)
Patrick: only for some apps
Drogus: for interactive apps, not for static apps that need to be indexed by Google
Andrzej: for all the apps
Adam: we need better tools on the backend in order to have a better developer experience
Piotr: Andrzej, would you write wikipedia as a SPA?
Andrzej: Yes.
Adam: What about SEO?
Andrzej: It's a myth that SPAs are not indexable. Google has an official document for that. It is additional work.
Patrick: You can use PhantomJS for SEO.
Adam: We've used PhantomJS for that, took a couple of hours.
8m28s
Can you introduce the framework you're representing here?
Andrzej: HexagonalJS is not a framework, it's an architecture guide. Uncle Bob (OOP) + Raganwald (AOP) + Hexagonal Architecture. It's more like a set of guidelines
Piotr: EmberJS - it does as much as it can for managing your SPA. it's not minimalistic, for good reasons (you don't have to write much code).
Patrick: Backbone, very small, minimal. you don't bring too much dependencies. you can choose what you want.
Adam: Angular, Two-way data binding is the key feature. Synchronization of HTML and your JS. Choose framework with data-binding. Ember is essentially a language, forces its own object model. Backbone as well. Hexagonal or Angular is pure JS.Your application can live outside of Angular.You could use Angular with a Hexagonal app. Backed by Google, more mature than Ember.
Andrzej: Data binding is not as important as you may think. Manual control is not that difficult. Hexagonal doesn't have data binding jilt-in. Apps are not about data changes, but about actions
Piotr: I agree that data binding is important. Both, Angular and Ember are good for big applications. Nested views, zombie views (backbone). Angular has its own compiler for DOM elements. You need to know how the compiler works. Angular uses dirty checking. Angular claims that your UI shouldn't have than 2000 elements. You're screwed if you have more.
Adam: We built a 100 rows, 500 columns table. We managed to do it with Angular. It's not that hard to do the UI part. Directives are like helpers for html.
22m6s
Do you have to take the mindset of the creator?
Adam: Most of the things in Angular are optional.If you don't use the HTML part, you lose a lot.
Andrzej: It's a problem of all of us here, including Hexagonal. We use different terminology for different things. All the frameworks are far from being Rails, we're not mature enough. All the frameworks are in their infancy years.
Patrick: It's easy to work with Rails and Backbone
Piotr: Ember has its own class model. It's done mainly for making it easy to optimise. Ember is about Convention over Congifuration. Rails in JS. Ember is like Rails, Backbone is like Sinatra. At some point you have to use more plugins if you start with something minimal. A lot of pain if you want to write a big app with a small framework.
Andrzej: I disagree. I would use a framework for a prototype or for a small app. Once the app grows, it has its own world. I don't want the framework to go into my way. I want to have the control over the applications. I'd use Ember for smaller apps, not for bigger apps.
27m23s
How to be involved in the community, how to learn the framework?
Adam: Angular has really good docs. All development happens on github.
Andrzej: Hexagonal has just started. It got the name just recently. We've used it for over a year. We have a strong team behind it. Our goal is to show the guidelines.
Piotr: Ember is 1.0RC now. Docs are better now. IRC is very active. Google Group.
Patrick: JavaScript and Ruby devs can help.
END
If you're interested in Single Page Apps, you may want to follow me on Twitter.
Saturday, February 23, 2013
Why do projects take so long?
Some projects take a long time to develop. In different contexts, the definition of "long" may vary. It was always interesting to me, what are the reasons for it. Recently, though, it became my obsession.
I've started collecting some thoughts on this topic.
Ask yourself and your teammates about the last project you've been working on. "Would we be able to implement the same result in 1 month? In 1 week?".
Surprisingly often, I'm answering to myself - yes, that would be possible, given some assumption. I've had similar answers from my colleagues.
Where does it come from?
Is it the known tendency to underestimating a problem by developers? I don't think so, as we're talking about a project, that has already happened. We know what is to be done. We are aware of edge cases.
"This is time it will be different, faster"
This is another popular trend among us, developers. Most of us are optimistic, even the experienced ones. It's not some kind of a student-syndrome (I'll do it tonight), but a well-thought statement. Is it really different and faster? Not always…
Where does this optimism come from? Good developers become better at solving technical problems. With each problem solved, we know that we solved the problem forever. We love solving problems, every day we're smarter by this attitude. We're progressing and the optimism may come from that.
It's almost impossible to get a second chance of working on the same project. What would that even mean from a business perspective? We rarely get that chance.
Is it the technology that let us think, that we could do better this time? That's a serious candidate. Every time, I switched to better technologies or to better architectures, I noticed the speed increase. I was more confident. I saw the results.
I remember a situation, back in 2004/2005. I was involved in preparing an estimate for a new project. The estimate was about 6 months for 4 developers (assuming ASP.NET). Very shortly after that I learnt Rails. I realised, that the project is perfect for Rails. It was a CRUD-based web app. I kept convincing the management to give it a try. No luck. Finally, I had a chance of coding live in front of some managers. I implemented the main path in about 1 hour (I was well prepared). That convinced them. We've finished this project in 1.5 month, with one junior programmer and me being mostly a PM and a Rails mentor.
What's the lesson? It's hard to tell. I'm not trying to say that only Rails was the reason. Motivation? The passion behind it? Trying to prove something? The focus? I think it was a combination of all of the above aspects.
Is it easy to repeat those aspects? Do they sound familiar?
Have you ever attended a hackathon?
There are many kinds of hackathons. What's most important in this context, is how much can be done in a very limited time. If you look at the results of Rails Rumble, some of the apps are quite big. Many features, everything is polished.
Hackathons are proves that we are able to develop apps quickly.
How can we apply hackathon lessons to our every-day projects? Is it possible?
What else can help us developing software faster?
I would love to know your opinions.
Angular or Ember? Congratulations, you've already won.
At the wrocloverb conference we've decided to have a Single Page Applications "fight". (The format of fight worked pretty well last year for the JRuby vs Rubinius battle).
We're having Ember, angular, Backbone and hexagonaljs representatives. As I'm representing the last one, during the last few days, I've did more research on the other alternatives.
There are huge differences between all the choices. Some of the frameworks are like Rails, some are more like Sinatra. Hexagonaljs is not even a framework.
I have been making notes on the differences, collected jokes on each of the opponents. It's going to be a great fight :)
Anyway.
I realised one thing. If you're wondering which of the frameworks, non-frameworks to choose, you have already won. You are already in the world of Single Page Applications. There's no wrong choice in here. You will be fine with any of the frameworks.
There's a warning, though. I know many people who entered this world and they don't want to come back to the non-SPA reality.
Congratulations, that was a good choice!
We're having Ember, angular, Backbone and hexagonaljs representatives. As I'm representing the last one, during the last few days, I've did more research on the other alternatives.
There are huge differences between all the choices. Some of the frameworks are like Rails, some are more like Sinatra. Hexagonaljs is not even a framework.
I have been making notes on the differences, collected jokes on each of the opponents. It's going to be a great fight :)
Anyway.
I realised one thing. If you're wondering which of the frameworks, non-frameworks to choose, you have already won. You are already in the world of Single Page Applications. There's no wrong choice in here. You will be fine with any of the frameworks.
There's a warning, though. I know many people who entered this world and they don't want to come back to the non-SPA reality.
Congratulations, that was a good choice!
Friday, February 22, 2013
Non-framework approach to JavaScript apps - hexagonal.js
This week we have officially launched and announced hexagonal.js.
The announcement was welcomed with a fair amount of interest. Jan Filipowski at the Arkency blog did a great job of explaining the basic ideas.
I'd like to cover the topic of hexagonaljs not being a framework.
What is a framework?
Some time ago I asked "What is a framework?". I liked the following answer:
I have a love/hate relationship with frameworks. That's why I struggled for months, what to do with the ideas that we're now calling hexagonal.js. I didn't want it to be a framework. That would ruin the whole experience.
Let me tell you a story on how it all started and why we didn't want it to be a framework.
The technical story of haxagonal.js
The first ideas were created when we were working on social web games at GameBoxed. Given the scale we were operating on (sometimes 4-5 social apps/games a month) we needed a high degree of reusability. Reusability requires good modularity. Often, we've had apps that have the same "logic", but they had much different GUI, sounds, FB integration etc.
We got the idea of use cases as objects from the DCI approach (DCI is much more than that!). We've experimented with the concept that it's the use-case that drives everything. Driving something (like playing sounds) meant calling it. Calling it directly meant creating a coupling between the use-case and the SoundAdapter, which didn't sound like a good idea.
One approach was to use events. The use case would trigger an event and the adapter would bind to it. It resulted in less coupling. It wasn't bad. To me, it wasn't yet the final solution, though. I didn't like the fact, that the use-case objects were full of "trigger someEvent" statements.
When I looked at the events, I realised that they happen usually at the beginning or at the end of a method in the use case.
Before, After....
Wait, wasn't that what AOP was about?
Introducing some simple AOP techniques (thanks to awesome Raganwald's library!), we have achieved exactly what was needed. This is what we currently call a Glue code. It's almost like a configuration, in most cases. No logic, just declarations.
Hexagonal architecture
We started with MVC in mind. The most basic rule of MVC is that when the model changes, the views are notified about it. After some time, we've realised that it's not only about views, unless you try to fit "playing sounds" into the View layer ;)
In a hexagonal architecture, GUI is just one of the adapters. It's usually the most important one, but technically, still, just an adapter.
In many apps, the GUI is the only adapter.
ServerSideAdapter, PusherAdapter, SoundAdapter, FirebaseAdapter, FacebookAdapter, LinkedInAdapter - those are just examples of the adapters, that we used so far.
It's not a framework
Given all of the above, we were struggling on how to bring this idea to people, without making them depend on any framework. The whole idea is a bit anti-framework.
Hexagonal.js is not even a library. It's mostly an architectural style adapted to JavaScript apps. We provide many examples (and more in progress..), that can guide you. You can copy them, fork them and have a good starting point.
It's probably a slightly unusual approach to deliver some ideas to you. It's not a framework, not a library.
Hexagonal.js is a set of good patterns that are extracted from real-world production apps. It was used to build dozens of apps, with a good speed of development.
You can look at the examples we already have. Look at the use case object, the glue and the adapters. It's a pattern that reappears in every hexagonaljs app. There is also an example of using it from a Rails app.
Tell us what you think about this approach. We've published it to bring more ideas. We're open for suggestions!
Thanks for reading.
The announcement was welcomed with a fair amount of interest. Jan Filipowski at the Arkency blog did a great job of explaining the basic ideas.
I'd like to cover the topic of hexagonaljs not being a framework.
What is a framework?
Some time ago I asked "What is a framework?". I liked the following answer:
In the case of a framework, your code is called by it. In the case of a library, your code call it. Rails is a framework, and provides libraries too.
I have a love/hate relationship with frameworks. That's why I struggled for months, what to do with the ideas that we're now calling hexagonal.js. I didn't want it to be a framework. That would ruin the whole experience.
Let me tell you a story on how it all started and why we didn't want it to be a framework.
The technical story of haxagonal.js
The first ideas were created when we were working on social web games at GameBoxed. Given the scale we were operating on (sometimes 4-5 social apps/games a month) we needed a high degree of reusability. Reusability requires good modularity. Often, we've had apps that have the same "logic", but they had much different GUI, sounds, FB integration etc.
We got the idea of use cases as objects from the DCI approach (DCI is much more than that!). We've experimented with the concept that it's the use-case that drives everything. Driving something (like playing sounds) meant calling it. Calling it directly meant creating a coupling between the use-case and the SoundAdapter, which didn't sound like a good idea.
One approach was to use events. The use case would trigger an event and the adapter would bind to it. It resulted in less coupling. It wasn't bad. To me, it wasn't yet the final solution, though. I didn't like the fact, that the use-case objects were full of "trigger someEvent" statements.
When I looked at the events, I realised that they happen usually at the beginning or at the end of a method in the use case.
Before, After....
Wait, wasn't that what AOP was about?
Introducing some simple AOP techniques (thanks to awesome Raganwald's library!), we have achieved exactly what was needed. This is what we currently call a Glue code. It's almost like a configuration, in most cases. No logic, just declarations.
Hexagonal architecture
We started with MVC in mind. The most basic rule of MVC is that when the model changes, the views are notified about it. After some time, we've realised that it's not only about views, unless you try to fit "playing sounds" into the View layer ;)
In a hexagonal architecture, GUI is just one of the adapters. It's usually the most important one, but technically, still, just an adapter.
In many apps, the GUI is the only adapter.
ServerSideAdapter, PusherAdapter, SoundAdapter, FirebaseAdapter, FacebookAdapter, LinkedInAdapter - those are just examples of the adapters, that we used so far.
It's not a framework
Given all of the above, we were struggling on how to bring this idea to people, without making them depend on any framework. The whole idea is a bit anti-framework.
Hexagonal.js is not even a library. It's mostly an architectural style adapted to JavaScript apps. We provide many examples (and more in progress..), that can guide you. You can copy them, fork them and have a good starting point.
It's probably a slightly unusual approach to deliver some ideas to you. It's not a framework, not a library.
Hexagonal.js is a set of good patterns that are extracted from real-world production apps. It was used to build dozens of apps, with a good speed of development.
You can look at the examples we already have. Look at the use case object, the glue and the adapters. It's a pattern that reappears in every hexagonaljs app. There is also an example of using it from a Rails app.
Tell us what you think about this approach. We've published it to bring more ideas. We're open for suggestions!
Thanks for reading.
Thursday, February 14, 2013
Frontend first
Some time ago, I blogged about the different phases of mental transition when working with JavaScript frontends. Here's the shorten version:
1. No-JavaScript phase
2. JQuery explosion
3. Page and Widget objects
4. Single Page Application
Once you're in phase 4 and you create apps this way, you realize that you don't need the backend in order to create the Single Page App. Even more, you shouldn't start with a backend.
Frontend first
This is the additional phase. Frontend first. In most of the typical situations, it's much better to start with a Single Page Application and use LocalStorage or some kind of a InMemoryServerSideAdapter for the first phases of the development.
Only after you know how the frontend works and what kind of server interaction it requires, it actually makes sense to start working on the backend.
We've tried this approach in several Single Page Apps and it worked great for us. It now seems like the most natural way of working.
to learn more about Single Page Applications.
Subscribe to:
Posts (Atom)