Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 18 | Comments: 72

filter by tags archive

Composite UI, the designer and IoC

time to read 2 min | 258 words

image

I am trying to think of a way to make this view work. It is a single view that contains more views, each of them responsible for a subset of the functionality in the view. This is the first time that I am dealing with smart client architecture for a long time.

It is surprising to see how much the web affect my thinking. I am having trouble dealing with the stateful nature of things.

Anyway, the problem that I have here is that I want to have a controller with the following constructor:

public class AccountController
{
	public AccountController(
		ICalendarView calendarView,
		ISummaryView summaryView,
		IActionView actionView)	{ }
}

The problem is that those views are embedded inside a parent view. And since those sub views are both views and controls inside the parent view, I can't think of a good way to deal with both of them at once.

I think that I am relying on the designer more than is healthy for me. I know how to solve the issue, break those into three views and build them at runtime, I just... hesitate before doing this. Although I am not really sure why.

Another option is to register the view instances when the parent view loads, but that means that the parent view has to know about the IoC container, and that makes me more uncomfortable.

It is a bit more of a problem when I consider that there are two associated calendar views, which compose a single view.

Interesting problem.

Purely declarative DSL

time to read 2 min | 291 words

Let us assume that we need to build a quote generation program. This mean that we need to generate a quote out of the customer desires and the system requirements.

The customer's desires can be expressed in this UI:

image

The system requirements are:

  • The Salary module is specification is a machine per every 150 users.
  • The Taxes module requires a machine per 50 users.
  • The Vacations module requires the Scheduling Work module.
  • The Vacations module requires the External Connections module.
  • The Pension Plans module requires the External Connections module.
  • The Pension Plans module must be on the same machine as the Health Insurance module.
  • The Health Insurance module requires the External Connections module.
  • The Recruiting module requires a connection to the internet, and therefore requires a fire wall of the recommended list.
  • The Employee Monitoring module requires the CompMonitor component

The first DSL that I wrote for it looked like this:

if has( "Vacations" ):
	add "Scheduling"
	
number_of_machines["Salary"] = (user_count % 150) +1
number_of_machines["Taxes"] = (user_count % 50) +1

But this looked like a really bad idea, so I turned to a purely declarative approach, like this one:

specification @vacations:
	requires @scheduling_work
	requires @external_connections
	
specification @salary:
	users_per_machine 150
	
specification @taxes:
	users_per_machine 50

specification @pension:
	same_machine_as @health_insurance

The problem with this approach is that I wonder, is this really something that you need a DSL for? You can do the same using XML very easily.

The advantage of a DSL is that we can put logic in it, so we can also do something like:

specification @pension: 
	if user_count < 500:
		same_machine_as @health_insurance
	else:
		requires @distributed_messaging_backend
		requires @health_insurance

Which would be much harder to express in XML.

Of course, then we are not in the purely declarative DSL anymore.

Thoughts?

Authorization DSL

time to read 1 min | 112 words

Here is a tidbit that I worked on yesterday for the DSL book:

operation "/account/login"

if Principal.IsInRole("Administrators"):
	Allow("Administrators can always log in")
	return

if date.Now.Hour < 9 or date.Now.Hour > 17:
	Deny("Cannot log in outside of business hours, 09:00 - 17:00")

And another one:

if Principal.IsInRole("Managers"):
	Allow("Managers can always approve orders")
	return

if Entity.TotalCost >= 10_000:
	Deny("Only managers can approve orders of more than 10,000")
	
Allow("All users can approve orders less than 10,000")

There is no relation to Rhino Security, just to be clear.

I simply wanted  a sample for a DSL, and this seems natural enough.

Looking for a new development laptop

time to read 1 min | 153 words

I am looking at getting a new laptop. This is something that should serve as a development machine, and I am getting tired of waiting for the computer to do its work. As such, I intend to invest in a high end machine, but I am still considering which and what.

Minimum Requirements are 4GB RAM, Dual Core, Fast HD, big screen.

Video doesn't interest me, since even the low end ones are more than I would ever want. Weight is also not an issue, I would be perfectly happy with a laptop that came with its own wheelbarrow.

I am seriously thinking about getting a laptop with a solid state drive, and I am beginning to wonder if quad core is worth the price. Then again, I am currently writing dream checks for it, which is why I feel like I can go wild with all the features.

Any recommendations?

ORM += 2

time to read 1 min | 136 words

I am going to give a talk about the high end usages of OR/M and what it can do to an application design.

I have about one hour for this, and plenty topics. I am trying to think about what topics are both interesting and important to be included.

Here are some of the topics that I am thinking about:

  • Partial Domain Models
  • Persistent Specifications
  • Googlize your domain model
  • Integration with IoC containers
  • Taking polymorphism up a notch - adaptive domain models
  • Aspect Orientation
  • Future Queries
  • Scaling up and out
    • Distributed Caching
    • Shards
  • Extending the functionality with listeners
    • Off the side reporting
  • Queries as Business Logic
  • Cross Cutting Query Enhancement
    • Filters
  • Dealing with temporal domains

Anything that you like? Anything that you would like to me to talk about that isn't here?

Rhino SecurityExternal API

time to read 2 min | 390 words

When I thought about Rhino Security, I imagine it with a single public interface that had exactly three methods:

  • IsAllowed
  • AddPermissionsToQuery
  • Why

When I sat down and actually wrote it, it turned out to be quite different. Turn out that you usually want to handle editing permissions, not just check permissions. The main interface that you'll deal with is usually IAuthorizationService:

image

It has the three methods that I thought about (plus overloads), and with the exception of renaming Why() to GetAuthorizationInformation(), it is pretty much how I conceived it. That change was motivated by the desire to get standard API concepts. Why() isn't a really good method name, after all.

For building the security model, we have IAuthorizationRepository:

image

This is a much bigger interface, and it composes almost everything that you need to do in order to create the security model that you want. I am at the point where this is getting just a tad too big, another few methods and I'll need to break it in two, I think. I am not quite sure how to do this and keep it cohesive.

Wait, why do we need things like CreateOperation() in the first place? Can't we just create the operation and call Repository<Operation>.Save() ?

No, you can't, this interface is about more than just simple persistence. It is also handling logic related to keeping the security model. What do I mean by that? For example, CreateOperation("/Account/Edit") will actually generate two operations, "/Account" and "/Account/Edit", where the first is the parent of the second.

This interface also ensures that we are playing nicely with the second level cache, which is also important.

I did say that this interface is almost everything, what did I leave out?

The actual building of the permissions, of course:

image

This is utilizing a fluent interface in order to define the permission. A typical definition would be:

permissionsBuilderService
	.Allow("/Account/Edit")
	.For(CurrentUser)
	.OnEverything()
	.DefaultLevel()
	.Save();

permissionsBuilderService
	.Deny("/Account/Edit")
	.For("Administrators")
	.OnEverything()
	.DefaultLevel()
	.Save();

This allow the current user to edit all accounts, and deny all members of the administrators group account editing permission.

And that sums all the interfaces that you have to deal with in order to work with Rhino Security.

Next, the required extension points.

NHibernate Queries: Find all users that are members of the same blogs as this user

time to read 3 min | 570 words

Let us assume that we have the following model:

  • User
    • n:m -> Blogs
      • n:m -> Users

Given a user, how would you find all the users that are members of all the blogs that the user is a member of?

Turn out that NHibernate makes it very easy:

DetachedCriteria usersForSameBlog = DetachedCriteria.For<User>()
	.Add(Expression.IdEq(userId))
	.CreateCriteria("Blogs")
	.CreateCriteria("Users", "user")
	.SetProjection(Projections.Id());
session.CreateCriteria(typeof(User))
	.Add(Subqueries.PropertyIn("id", usersForSameBlog))
	.List();

And the resulting SQL is:

SELECT this_.Id        AS Id5_0_,

       this_.Password  AS Password5_0_,

       this_.Username  AS Username5_0_,

       this_.Email     AS Email5_0_,

       this_.CreatedAt AS CreatedAt5_0_,

       this_.Bio       AS Bio5_0_

FROM   Users this_

WHERE  this_.Id IN (SELECT this_0_.Id AS y0_

                    FROM   Users this_0_

                           INNER JOIN UsersBlogs blogs4_

                             ON this_0_.Id = blogs4_.UserId

                           INNER JOIN Blogs blog1_

                             ON blogs4_.BlogId = blog1_.Id

                           INNER JOIN UsersBlogs users6_

                             ON blog1_.Id = users6_.BlogId

                           INNER JOIN Users user2_

                             ON users6_.UserId = user2_.Id

                    WHERE  this_0_.Id = @p0)

You need to control the stack

time to read 3 min | 401 words

I have a fairly strong opinions about the way I build software, and I rarely want to compromise on them. When I want to build good software, I tend to do this with the hindsight of what is not working. As such, I tend to be... demanding from the tools that I use.

What follows are a list of commits logs that I can directly correlate to requirements from Rhino Security. All of them are from the last week or so.

NHiberante

  • Applying patch (with modifications) from Jesse Napier, to support unlocking collections from the cache.
  • Adding tests to 2nd level cache.
  • Applying patch from Roger Kratz, performance improvements on Guid types.
  • Fixing javaism in dialect method. Supporting subselects and limits in SQLite
  • Adding supporting for paging sub queries.
  • Need to handle the generic version of dictionaries as well.
  • Override values in source if they already exist when copying values from dictionary
  • Adding the ability to specify a where parameter on the table generator, which allows to use a single table for all the entities.
  • Fixing bug that occurs when loading two many to many collection eagerly from the same table, where one of them is null.

Castle

  • Fixing the build, will not add an interceptor twice when it was already added by a facility
  • Generic components will take their lifecycle / interceptors from the parent generic handler instead of the currently resolving handler.
  • Adding ModelValidated event, to allow external frameworks to modify the model before the HBM is generated.
  • We shouldn't override the original exception stack

Rhino Tools

  • Adding tests for With.QueryCache(), making sure that With.QueryCache() can be entered recursively. Increased timeout of AsyncBulkInsertAppenderTestFixture so it can actually run on my pitiful laptop.
  • Adding support for INHibernateInitializationAware in ARUnitOfWorkTestContext
  • Adding error handling for AllAssemblies. Adding a way to execute an IConfigurationRunner instance that was pre-compiled.
  • Will not eager load assemblies any more, cause too many problems with missing references that are still valid to run

Without those modifications, I would probably have been able to build the solution I wanted, but it would have to work around those issues. By having control the entire breadth and width or the stack, I can make sure that my solution is ideally suited to what I think is the best approach. As an aside, it turn out that other people tend to benefit from that.

FUTURE POSTS

  1. RavenDB 3.0 New Stable Release - 7 hours from now
  2. Production postmortem: The industry at large - about one day from now
  3. The insidious cost of allocations - 2 days from now
  4. Buffer allocation strategies: A possible solution - 5 days from now
  5. Buffer allocation strategies: Explaining the solution - 6 days from now

And 3 more posts are pending...

There are posts all the way to Sep 11, 2015

RECENT SERIES

  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    01 Sep 2015 - The case of the lying configuration file
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats