Wednesday, 12 March 2014

Open Floorplans? Commit and do it right or don't do it at all!

I've only worked in closed floorplan offices for a little while and that was because the actual building was designed for housing. It was an old building and after some point it made more sense for the owner to lease it for business use than housing. So, we would be around 6-8 people per room with aligned desks, and no vertical desk panels and no carpet either. I can't say i would complain. The generated noise was kept low; we weren't so many after all, the level of visual distractions were also very low, the room only had a single entrance so no passthrough traffic occurred and the single, large, window had a curtain of sorts.


I only stayed there for 6 months or so, then the company moved to new offices which where totally open it was strange for everyone.  Immediately some rules where set: people should maintain their voice level low; dress code for everyone (at  minimum smart casual). Fortunately the whole floor was carpeted and desks had desk panels; albeit made from MDF wood. The windows stretched from end-to-end and we were positioned on the 4th floor. This meant that external visual distractions were kept at minimum and while people were moving about constantly the office was spacious enough that it didn't attract attention. It also helped that the desks were oriented vertically and positioned far from the main path ways. Still, having ~60 people in the same space generated enough noise so that a constant hum existed.

In my next workplace, again a small company of 10 I began with a small office and then we moved to a open floor office. They were right next to a constant-traffic highway, with sound insulation being mediocre at best. The windows were again across the wall but unfortunately they stretched from the floor all the way up to the ceiling so even though we werre on the 2nd floor; traffic was continually in our line of sight. A carpet was not installed and the desk panels were 30% a fabric, 20% sandblasted-like see-though plastic and the rest aluminum. For me it was horrible.The constant visual distractions by the traffic as well as any in the workplace itself with the constant noise from the traffic made it a perpetual nightmare. Although some people tried to keep their voices low others would just blast through the room with booming voices. Not having carpets, sound insulating desk panels or wall covers made sure that i could hear a coworker's keyboard from 5 meters away - and we didn't use any mechanichal ones.

The worst part of the open workplan though is that it strips away the feeling of privacy and seclusion, the latter being a very important element for most of us. Unfortunately it introduces a feeling of constant availability. You see the person across the room and it is very easy to assume that you can speak to him, to ask him a question or just attract his attention. There is no visual barrier and this extends to our behaviour as well. Keeping myself in the "zone" was an uphill battle.

After reading http://adevelopersvoice.com/2014/03/03/i-hate-open-floorplans-it-makes-roger-come-out/. I thought that i should share my experience on the subject with perhaps with some Do's and Don't's. The main idea for me is that an open floorplan is feasable - and probably welcome - but only if commit yourself into doing it right!

Generally speaking the visual distractions must absolutely be kept at minimum. This means window blinds, keeping desks as far from pathways as possible, vertical desk panels, constant contiguous lighting. Pathways to any and all exits should have vertical screens; we don't have to be distracted everytime somebody comes in or goes out. This is particularly important as the workforce increases; toilet/coffee/cigarette/phone runs increase in parallel.

For window covers, although window blinds are easier to maintain and clean, i would strongly suggest to install fabric curtains. They filter light in a homogeneous fashion and they also work as vertical sound dampeners for both external noises as well as internal.

Carpets. Carpets everywhere! It makes a huge difference in dampening voices, clicks and other (mainly sharp) noises and you don't have to install something expensive either.

If you absolutely have to be near high-traffic areas invest into sound insulation. This is not optional, constant noise can -and eventually will- drive you crazy!

Wood is a brilliant, natural, soundprofing material that is also very pleasing to the eye. Don't install MDF desks, panels and other furniture if you have the option.

People shouldn't just walk around the office all the time. If managers need to talk to people they should also use the phone even if the other person is two desks away. This helps for both visual and audible distractions as we usually don't yell at the phone. If you make this a habit and combine it with sound-insulated desk panels the sound is almost guaranteed to not travel very far.

Don't force IM usage for anything over 2 sentences. IM's are a poor medium for discussions. For me they are actually frustrating since you usually don't convey your full thoughts on a subject, plus the imposed waiting game for replys is a drag.

Don't force headphones. I don't want to constantly have someting covering my ears and/or listen to music. I'm not a DJ and I don't work in an airport!

Do group divisions and/or teams. Sales and Marketing are probably talking all the time, they could also be in a different room, building or even country for all I care. They definitely don't belong in the same room full of developers.

If management is not also included in this setting, don't do it. Lead by example and have the CEO work in the same space with everybody else.

Finally, just because I am sitting right there and you can see me, it does not mean that I am available and/or you can intrude just because you have to say something. This is not an inherent problem of open floorplans but they enable it. Respect the other person and unless there is a fire on hesitate to distract him.

Wednesday, 3 April 2013

Getting the (LocalResource) ResourceManager from an asp.net website webform

To get the ResourceManager for LocalResources in a asp.net website webform use this snippet

    protected System.Collections.Hashtable GetLocalResourceStringEntries()
    {
        var localResourceStringEntries = new System.Collections.Hashtable();
        var f = typeof(TemplateControl).GetField("_resourceProvider", BindingFlags.NonPublic | BindingFlags.Instance);
        if (f == null)
            return localResourceStringEntries;
        var resourceProvider = (System.Web.Compilation.IResourceProvider)f.GetValue(this);
        if (resourceProvider.ResourceReader == null)
            return localResourceStringEntries;
        foreach (System.Collections.DictionaryEntry de in resourceProvider.ResourceReader)
        {
            if (de.Value is String)
                localResourceStringEntries[de.Key] = de.Value;
        }
        return localResourceStringEntries;
    }

Tuesday, 14 June 2011

On Google PageRank and SEO

Content aggregators are bad. They just rely on original work and using seo/sem techniques manage to push their content above the original ones.

A friend had a problem where his original post enjoyed a brief appearance on the first pages of google and then it got picked up by an aggregator/scraper. It went downhill from there.

https://www.sumo.gr/2011/06/01/ta-10-kalytera-nhsia-toy-kosmoy/

So here is some free (as in free beer) advice on SEO:

The hyperlinks of the articles should ideally have the form of
* https://www.sumo.gr/{date}/{article-title}[B].html[/B]
The html extension is important as it essentially tricks the google bot to think that you are serving a static page (vs a dynamic) and so it's boosted

* Even better, the link page and file title should be in its original language:
https://www.sumo.gr/2011/06/01/Τα-10-καλύτερα-νησιά-του-κόσμου.html
So, searching for "τα καλύτερα νησιά" there should be partial and direct correlation to an address

* IMG tags should always have an ALT text! Ideally it should be normal text so *that* can also be included in the index. Normally the filename it self should be human readable.

* The page title must not include the site's name in each and every page/article, only the article's title

* The <meta name="keywords" /> is very bad. So much, that i believe that it appears as spam to the bot. Let it have 10-15 keywords (even if for every language although the original language is the only important) and non-repeatable. Only the "hawaii" keyword appears 5 times! And the title appears something like 7-8 times

* The <meta name="description" /> is a little large. Keep it close to 140-150 characters (now its 167, google keeps 160, bing 150)

Here i should say that allegedly meta description/keyword are not used in the algorithm (since 2009) but that doesn't mean that are not getting flagged as spam

* Content-Encoding:gzip . 'nuff said. Generally the site suffers from a performance perspective and it lowers your pagespeed rank

* caching:
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: ...1981
Really? This does not influence pagerank directly but pagespeed. And *that* influences pagerank

In fact, the latest trend in google search is giving direct preference to pagespeed

* passing the w3c validator may or not may be important
http://validator.w3.org/check?uri=https%3A%2F%2Fwww.sumo.gr%2F2011%2F06%2F01%2Fta-10-kalytera-nhsia-toy-kosmoy%2F&charset=%28detect+automatically%29&doctype=Inline&group=0

Ignoring the various pseudo-attributes for facebook and meta data like rel (and which generally are not considered "braking" there are actual html errors. The most important i could detect is not cleaning double quotes. Take for example the text <<Το πρώτο νέο "σπίτι" της ανθρωπότητας>>. if this is placed in a title attribute (and it is) then the whole element brakes, disrupting the bot's work:
<a href="..." title="Το πρώτο νέο "σπίτι" της ανθρωπότητας" is read like
<a href="..." title="Το πρώτο νέο " σπίτι" της ανθρωπότητας" where <<σπίτι>> is a bad attribute.

also, <<Stray end tag a.>> not good, bots expect quality html

Generally the aggregator's w3c validation is much much better and this may boost them instead of you.

This definitely not an exhaustive list but just some things i saw in a short glance

Thursday, 28 April 2011

NHibernate and the missing OperatorProjection

It's been a long while, unfortunately i can't seem to find time to tend to my blog :/

I've been using NHibernate for some years now and although i consider it to be great there are some things that bug me. I've been looking at some questions over at SO (like for example http://stackoverflow.com/questions/4243890/nhibernate-restriction-with-sum-of-2-columns and http://stackoverflow.com/questions/2936700/nhibernate-criteria-how-to-filter-on-combination-of-properties) and it seems that i am not the only one that has this problem.

I consider it odd that not all standard SQL-92 operators -mathematical and maybe bitwise / unary ?- are supported in an intuitive way (there, i said it). In fact there is specific implementation for each of the supported conditional operators via Restrictions (Eq, Lt, Le etc).

I consider the Criteria API the strongest query engine for NHibernate and if you sweeten it with some LINQ candy just to get compilation support you can get the most out of it.

So, i looked about to find out how hard it would be to make an OperatorProjection.

Apparently it wasn't that hard :-)

The solution was to create my own Projection that is responsible to generate the necessary SQL, which derives from NHibernate's own SimpleProjection.

Lets say, for the sake of argument, that i want to return a given property with an added number.

This is pretty easy in hql, its like writing sql:
select t.Id, t.Duration, t.Duration + 5 from WorkSpecification

In vanilla Criteria API its not that simple and it hides a couple of traps:
crit.SetProjection(Projections.Id(),
    Projections.Property("Duration"),
    Projections.SqlProjection("{alias}.DaysDuration + 5",
                              new[] {"DaysDuration"},
                              new[]
                                  {
                                      NHibernateUtil.Int32
                                  }));

Its not simple because you have to write SQL and that means that the "DaysDuration" reference inside the SqlProjection means directly to a Column named "DaysDuration" and that point the ORM looses its power and flexibility.

Secondly the {alias} part commands the Criteria engine to inject at that point the alias of the root entity. That distinctively destroys any hope to make joins and apply the desired projection to the joined row (you can make subqueries via DetachedCriteria but that's not the same).

With OperatorProjection it can be written as

crit.SetProjection(Projections.Id(),
               Projections.Property("Duration"),
               new ArithmeticOperatorProjection("+",
                                                NHibernateUtil.Int32,
                                                Projections.Property("Duration"), Projections.Constant(5))
);


which generates this piece of SQL
SELECT this_.Id as y0_, this_.DaysDuration as y1_, (this_.DaysDuration + 5) as y2_ FROM WorkSpecification

The ugly part is that you pass the operator symbol as a string (but we may be able to do something about it as you will see in part 2) but then again now you don't need to rely to SQL. The only thing required is knowledge of the domain.

And since the Restrictions API also includes IProjections as parameters now this is also feasable:

zcrit.Add(
    Restrictions.Eq(new ArithmeticOperatorProjection("+",
                                    NHibernateUtil.Int32,
                                    Projections.Property("Duration"), Projections.Constant(5)
                                    )
                                    , 6
         );

which generates this piece of SQL
SELECT this_.(…) FROM WorkSpecification this_ WHERE (this_.DaysDuration + @p0) = @p1; @p0 = 5, @p1 = 6

Interestingly and as a side benefit Microsoft's SQL Server also uses the + operator to concatenate strings. And the result of the experiment was...

zcrit.Add(
        Restrictions.Eq(new ArithmeticOperatorProjection("+",
                            NHibernateUtil.String,
                            Projections.Property("FirstName"), Projections.Constant(" "), Projections.Property("LastName")
                            )
                        , “foo bar”
                        )
    );

which generates this piece of SQL
SELECT this_.(…) FROM PersonSpecification this_ WHERE (this_.FirstName + @p0 + this_.LastName) = @p1;
@p0 = ' ', @p1 = 'foo bar'

So what makes all this happen? Check it out below:
public abstract class OperatorProjection : SimpleProjection
    {
        private readonly IProjection[] args;
        private readonly IType returnType;
        
        private string op;
        private string Op { get { return op; }
            set
            {
                var trimmed = value.Trim();
                if (System.Array.IndexOf(AllowedOperators, trimmed) == -1)
                    throw new ArgumentOutOfRangeException("value", trimmed, "Not allowed operator");
                op = " " + trimmed + " ";
            }
        }

        public abstract string[] AllowedOperators { get; }

        protected OperatorProjection(string op, IType returnType, params IProjection[] args)
        {
            this.Op = op;    
            this.returnType = returnType;
            this.args = args;
        }

        public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
        {
            SqlStringBuilder sb = new SqlStringBuilder();
            sb.Add("(");

            for (int i = 0; i < args.Length; i++)
            {
                int loc = (position + 1) * 1000 + i;
                SqlString projectArg = GetProjectionArgument(criteriaQuery, criteria, args[i], loc, enabledFilters);
                sb.Add(projectArg);

                if (i < args.Length - 1)
                    sb.Add(Op);
            }
            sb.Add(")");
            sb.Add(" as ");
            sb.Add(GetColumnAliases(position)[0]);
            return sb.ToSqlString();
        }

        private static SqlString GetProjectionArgument(ICriteriaQuery criteriaQuery, ICriteria criteria,
                                                       IProjection projection, int loc,
                                                       IDictionary<string, IFilter> enabledFilters)
        {
            SqlString sql = projection.ToSqlString(criteria, loc, criteriaQuery, enabledFilters);
            return StringHelper.RemoveAsAliasesFromSql(sql);
        }

        public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
        {
            return new IType[] { returnType };
        }

        public override bool IsAggregate
        {
            get { return false; }
        }

        public override bool IsGrouped
        {
            get
            {
                foreach (IProjection projection in args)
                {
                    if (projection.IsGrouped)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
        {
            SqlStringBuilder buf = new SqlStringBuilder();
            foreach (IProjection projection in args)
            {
                if (projection.IsGrouped)
                {
                    buf.Add(projection.ToGroupSqlString(criteria, criteriaQuery, enabledFilters)).Add(", ");
                }
            }
            if (buf.Count >= 2)
            {
                buf.RemoveAt(buf.Count - 1);
            }
            return buf.ToSqlString();
        }
    }

Which is not really complicated and in fact is modified code from NHibernate's own Projections.SqlFunction(), and is a handy-dandy abstract class in case some one wants to implement some other operator. Note that the above class expects pairs of projections so it is not suitable for Unary Operators, although the only thing that has to change is the ToSqlString() method.

So the actual usable implementations look like this:

public class ArithmeticOperatorProjection : OperatorProjection
    {
        public ArithmeticOperatorProjection(string op, IType returnType, params IProjection[] args)
            : base(op, returnType, args)
        {
            if (args.Length < 2)
                throw new ArgumentOutOfRangeException("args", args.Length, "Requires at least 2 projections");
        }

        public override string[] AllowedOperators
        {
            get { return new[] { "+", "-", "*", "/", "%" }; }
        }
    }

    public class BitwiseOperatorProjection : OperatorProjection
    {
        public BitwiseOperatorProjection(string op, IType returnType, params IProjection[] args)
            : base(op, returnType, args)
        {
            if (args.Length < 2)
                throw new ArgumentOutOfRangeException("args", args.Length, "Requires at least 2 projections");
        }

        public override string[] AllowedOperators
        {
            get { return new[] { "&", "|", "^" }; }
        }
    }

You might notice that during sql generation i explicitly place the generated sql inside parenthesis () because, well they don't really hurt :-P.
Jokes aside, i haven't tested this in enough complicated scenarios to see if it behaves properly without parenthesis. Besides that, in the case of using multiple operators side by side, there is operator precedence that has to be taken into account, and at least for now there is no code to detect and/or fix that.

So it all boils down to the modular nature of NHibernate and the ability to write your own tools without having to necessarily modify the source. Can you say "win" ?

Thursday, 2 September 2010

Forcing a build on when Visual Studios' Debugger starts

It been a while but boy have i been busy :/

Having read http://webproject.scottgu.com/CSharp/UserControls/UserControls.aspx and http://weblogs.asp.net/scottgu/archive/2005/08/28/423888.aspx and trying to implement it i found myself in a nasty situation concerning 2 problems. First of all when an error occurs on the markup side of a UserControl/Page/etc the debugger with show the error not on the file that exists on the external library but on the file that we copied in our Web Application/Site. Its quite easy when making very small changes to get confused and make the changes on the stale file. I haven't found a neat solution on this and unfortunately the solution with the embedded usercontrols didn't work for me. Maybe it has something to do with Visual Studio 2008


Secondly, and quite importantly, hitting F5 to fire up the debugger will not guarantee a build! The reason, at least with Web Applications, is that changes on markup files will do not mark the library as dirty. In fact, any "Content" file has the same effect. So changing some important bit that does not change any code file and then starting the debugger will not trigger a build and so, since we are using copy/paste deployment and this depends on the pre-build event, the actual file that the application will use is stale. I find it very funny that msdn's MVP's actually advise to do a manual build. Surely there must be a better way!


After some digging around i found that the user can tamper with Visual Studio's event via the Macro Designer.
The initial implementation used this code part http://www.mztools.com/articles/2007/mz2007020.aspx
but i soon found out that even when the debugger is running, when entering Content files the ide will change to designer mode. So after searching the various exposed events i made this little simple fragment

    Private _curDebugState As EnvDTE80.dbgProcessState

    Public Sub debuggerStateChangedHandler( _
        ByVal NewProcess As EnvDTE.Process, _
        ByVal processState As EnvDTE80.dbgProcessState) _
        Handles DebuggerProcessEvents.OnProcessStateChanged
        If _curDebugState = dbgProcessState.dbgProcessStateStop And processState = dbgProcessState.dbgProcessStateRun Then
            DTE.ExecuteCommand("Build.BuildSolution")
        End If
        _curDebugState = processState
    End Sub

There are of course other commands like Build.BuildSelection, Build.RebuildSolution so choose your preference and you're set!

Thursday, 21 January 2010

Enabling Filters on mapped entities

I was trying to figure out if I could persuade NHibernate to enable filters on my <many-to-one /> entities and i fell on this discussion http://bit.ly/6W7WIA on the nhibernate-development google group. In short, <many-to-one /> filters should not work because filters where designed to filter data, not modify the domain.A valid viewpoint but i needed that functionality.


I have to think that filters should work out-of-the box and the developer should be responsible of enabling or disabling them. The reason is that i have a setup, that the represented domain can only reflected using filters. That is, applying WHERE clauses with dynamic parameters that are generated from the UI and that parameters remain the same for the length of the Request. As such the WHERE attribute on the class


Digging up the NH 2.1.2 source code i've found the single piece of code that is responsible for the behaviour.
Open up the NHibernate.Loader.Entity.EntityJoinWalker class and at approximately line 24 exists this piece of code:


SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
      //include the discriminator and class-level where, but not filters
      .Add(persister.FilterFragment(Alias, new CollectionHelper.EmptyMapClass<string, IFilter>()));
if you change it to

SqlStringBuilder whereCondition = WhereString(Alias, uniqueKey, batchSize)
       .Add(persister.FilterFragment(Alias, enabledFilters));

any enabled filters will be applied to your <many-to-one /> mapped entities as long as the filter exists on the entity definition mapping.

This little modification additionally enables filters for ISession.Get() and it works normally with lazy loading. If you are going to use ISession.Get() note that the cache is hit first before going to the datastore. In my setup, because the filter parameter defines a different entity instance for a given entity-id the second-level cache is not (and must not) be used, so take that into consideration before applying the modification to your solution.


I am thinking that if we could pass a parameter on the WHERE attribute on the class mapping (and ensure that this where fragment is used on ANSI-joins) none of this would have a reason to exist

Wednesday, 20 January 2010

Many-to-one and Composite-id mapping with NHibernate

Nhibernate's reference documentation sometimes leaves something to be desired. I was looking for the correct syntax to map a which has a and the documentation did not discuss it and a google search revealed nothing. While poking around the 'nhibernate-mapping.xsd' i found out that the element supports having elements underneath it so as to have the following syntax


<many-to-one name="Foo">
  <column name="FK_Column1">
  <column name="FK_Column2">
</column>


where the Foo class is mapped as
<class name="Foo" table="Foo">
  <composite-id class="FooCompId">
    <key-many-to-one name="SomeEntityA" column="PK_Column1">
    <key-many-to-one name="SomeEntityB" column="PK_Column2">
  <composite-id>
  ....
</composite-id>


note here that the Foo class uses 2 properly mapped classes (SomeEntityA and SomeEntityB) hence the <key-many-to-one/>
interestingly i used this as part of a <subclass /> element and it worked normally.

And to map a <bag /> of "Foo" from an other entity this syntax worked

<bag name="Foos" inverse"true">
  <key>
    <column name="FK_Column1">
    <column name="FK_Column2">
  </key>
  <one-to-many class="Foo" />
</bag>

the only requirement is that the order of the columns declared must match the order of the <key-many-to-one/> declared in the composite-id