What a good web2py application architecture looks like?

194 views
Skip to first unread message

mfarees...@gmail.com

unread,
Nov 17, 2016, 7:02:19 AM11/17/16
to web2py-users
Hi,
I need some help from experienced web2py developers and creators. I am creating a new application and would like to know what a good architecture for a web2py application looks like. Here is the architecture diagram of the past web2py projects I have worked on.



Thin controllers and thick models is how I'm thinking of proceeding. The controllers talk to the database only via Business Objects (BO). Only BOs can access the database. There is a separate folder for the BOs inside the modules folder.
app_name -> modules -> businessObjects -> DALs -> DalOfBO
Each BO file contains a class for that BO and some methods. Should the methods have database queries in the same file or should there be a different file for the DAL operations, for each BO?
Is this structure appropriate? If not, how can I make it better in order to make the development and maintenance of code easier.
Thanks

Leonel Câmara

unread,
Nov 17, 2016, 10:24:09 AM11/17/16
to web...@googlegroups.com
It seems you're replacing controllers with business objects, which seems like unnecessary complexity for me.  
  
That's the usual style of programming in Java and very "enterprisey" but I personally hate it as the business objects tend to grow and grow and eventually you can't keep track of all the side effects you have when you call one of their methods. 
  
The way I usually structure my web2py projects is, each entity (together with related entities) is in their own model file, for each entity I also have a controller file with the same name, the controller file has all the usual CRUD methods for that entity.  
  
KISS (Keep it simple stupid)  
  
Eventually, you will want some of what you call "business objects" but that's something that comes late in a project and that you get through refactoring, when you can identify components that are quite well self-contained and independent. For instance, in my projects, I have extracted the user notifications logic into their own "business object" as it's something that is independent from all the rest and saves a lot of lines of code in each controller that will want to send notifications to the user. The thing is, you don't know what will make the development and maintenance of the code easier until you have a few regular controller functions programmed and you can see what's worth refactoring into a module/"business object".

Val K

unread,
Nov 17, 2016, 1:05:22 PM11/17/16
to web2py-users
BO seems like stored procedures that expose secure interface to DB, but if it is your aim I think it would be better and more universal to have pure stored procedures at DB-side, no?
Message has been deleted
Message has been deleted

mfarees...@gmail.com

unread,
Nov 18, 2016, 12:30:54 AM11/18/16
to web2py-users
@Leonel Câmara
Thanks for your input on this. Perhaps I didn't explain the structure very well. I do have controllers and they have the same as some of the BOs. But not every BO has its own controller. There are some BOs that only communicate with BOs and not with controllers. Also, the controllers have the usual CRUD functions which call the the BOs CRUD method. So, for example a user needs to be read here's how the application flow is designed like,
The browser calls the user controller's GET method. That method calls the User BO's read_user method. This read_user method calls the read method in dalUser  file (which is inside the DALs folder)


So what you're saying is that instead of having the User (BO) and dalUser, I should have a file called user inside the models folder and that file should directly talk to the DB, is that correct?

Should I convert the query result to a user object or use the query result as it is on the view?

mfarees...@gmail.com

unread,
Nov 18, 2016, 12:40:49 AM11/18/16
to web2py-users
@Val K
Thanks but I'm not using stored procedures. I have DAL queries in which the where clause is manipulated via method parameters. So the code would look something like this,
def get_user(id=None, first_name=None):
return db((db.auth_user.id == id) & (db.auth_user.first_name == first_name)).select()

Leonel Câmara

unread,
Nov 18, 2016, 4:55:42 AM11/18/16
to web2py-users
def get_user(id=None, first_name=None):
return db((db.auth_user.id == id) & (db.auth_user.first_name == first_name)).select()

This code seems very wrong. Because if the id is None then it will never return anything. If the id is not None then why do you care about first_name?

It seems to me, all your BOs are doing is obfuscating the DAL interaction.  
  
Please read:




mfarees...@gmail.com

unread,
Nov 18, 2016, 5:19:59 AM11/18/16
to web2py-users
You are right, that code was wrong. It was just to give an idea of fetching a user based on id or first name, if either is provided. Here is a better version to explain how I write queries without using SP. 
 
def get_user(id=None, first_name=None):
data = None
if id and not first_name:
data = db((db.auth_user.id == id)).select()
elif not id and first_name:
data = db(db.auth_user.first_name == first_name).select()
else:
pass
return data

Leonel Câmara

unread,
Nov 18, 2016, 7:25:50 AM11/18/16
to web2py-users
Note that the code is still wrong because get_user implies it will only return 1 user and this may return several users that have the same first name, you probably mean email or username. This is exactly the problem with this kind of stuff, you are creating a leaky abstraction on top of the DAL which may hide bugs that are then harder to track.

mfarees...@gmail.com

unread,
Nov 18, 2016, 7:38:43 AM11/18/16
to web2py-users
This is partial code. After fetching the data I convert the rows to a list of objects and return it to the controller.
What is a better way to access DAL then?
I am going through the link you shared earlier.

Leonel Câmara

unread,
Nov 18, 2016, 8:01:23 AM11/18/16
to web2py-users
For me the best way to access the DAL is directly in the controllers, "business objects" like the ones you're creating are something that should come late in a project. For instance, if you notice that many controllers are always doing the same query. The best way to refactor that code is not even necessarily a class like your business objects, it may be a simple decorator you apply to the controllers that need them (like auth.requires_login()). The point is, you are creating a bunch of code for each business object you don't even know is needed at this point, that code creates overhead and may not even make your code shorter or more readable.

mfarees...@gmail.com

unread,
Nov 18, 2016, 8:12:52 AM11/18/16
to web2py-users
I understand your point now. But if controllers are accessing the DAL then what goes in the models and modules? The modules will have the BO (later), what else?

Leonel Câmara

unread,
Nov 18, 2016, 10:54:51 AM11/18/16
to web2py-users
Yes modules are a good place for BOs and for various tools and utils.

In the models go the table definitions.

Jim S

unread,
Nov 18, 2016, 10:57:39 AM11/18/16
to web2py-users
For me, I mostly use the DAL directly in controllers.  

But, I have a few areas where there is really complicated business logic that is needed by multiple controller functions.  Instead of repeating that complicated logic in the controller, I've created classes (stored in /modules) that I import and execute in my controller functions.  But as I said, there are very few.  Out of hundreds of controller functions, separate classes are used in only a couple dozen.

Using the DAL directly in controller methods is a big part of why you can develop so quickly using web2py.

What I try to do is keep it simple.  Use the DAL directly when appropriate and only use classes/objects to keep from repeating yourself.

Just my 2 cents...

-Jim 

Richard Vézina

unread,
Nov 18, 2016, 2:08:49 PM11/18/16
to web2py-users
I was going to add that, but Jim mention it... You can first do what Leonel says, keep it simple and not create complex object at first that may lead to overlapping or side effect when you want to share method among object and instead just write controller function and organize in "module" like fashion (I put module between quotes here as controllers files are not properly module). When you discover that you some controller helper function (function that exist beside controller function) are useful in more then one controller file, you put them in modules/some_file.py and import them where you need them... This is from my point of view the way most web2py users are doing as most of us are in Agile mode and not such kind of waterfalls development where you plan things in details before implement anything...

Good luck

Richard

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Carlos Zenteno

unread,
Nov 18, 2016, 5:17:24 PM11/18/16
to web2py-users
You may want to have a look at Sahana Eden. It is open source.

They basically use the models to initialize everything and to load modules.
The modules can be "models" as in SQL tables or they can be code as
in (probably) "business objects".

Their software is used in a myriad of applications so it is structured to have
a lot of settings, initialization and modules that a "normal" app would not need.


mfarees...@gmail.com

unread,
Nov 22, 2016, 1:45:56 AM11/22/16
to web2py-users
I'll definitely keep these tips in mind. Thank you ppl.
Reply all
Reply to author
Forward
0 new messages