Hledáme webového programátora

Prosím o sdílení.

Do liberecké IT firmy hledáme šikovného programátora v Javascriptu/C#. Přichází velký webový projekt, který bude minimálně na 1 rok. A po něm budou následovat další skvělé projekty.
Jsme firma, kde jsou lidé spokojení, s téměř nulovou fluktuací, od nás prostě lidi neodchází 🙂

Jak se u nás pracuje?
Pracujeme v nejnovějším Visual Studiu na výkonných notebocích v prostorných kancelářích. Používáme AngularJs + MVC, píšeme si unit testy, máme i vlastní testery. Na continuous intergration používáme Team City, pro verzování Git. Snažíme se o kvalitu.

Kdo jsme?
Jmenujeme se ST-Software a jsme dceřinná společnost od Swiss Timingu. Vyvíjíme software pro velké sportovní události, některé sporty na olympiádě, plavecké a jachtařské závody, atd…

Takže pokud jsi chytrý, rád se učíš nové věci a umíš C# + Javascript, tak se určitě ozvi na mail votrubec.d@st-software.com.

Sdílejte, lajkujte, přeposílejte, tweetujte ….

How to speed-up generating PDFs via TMS Flexcel

In my current project we needed to generate lot of PDFs from the same excel template.  For this we use TMS Flexcel library. It is a simple library for generating Excel or PDF files in .NET. It loads a xls template from filesystem, populates it with data and that’s it. Quite easy.

But generating tons of files in a cycle can be a pain, because the template has to be loaded from file system in every iteration. That can be performance problem. The solution is to read the template into MemoryStream and then in each iteration create new XlsFile object from this memory stream.

The data from DotTrace showed that almost 15% of operations was spent on reading from file-system. 15% may not be that much, but it is definitely worth it, when generating files in a loop.

Old unoptimized code

foreach (Order order in orders)
{
    //Load xls template from file system
    XlsFile template = new XlsFile("path/to/template.xlsx");
    
    //Populate template with variables
    report.SetValue("Order_Number", order.Code);
    report.SetValue("Order_CustomerName", order.CustomName);
    //... etc

    //Generate the report (after that the template contains data from this iteration, and has to be re-created)
    report.Run(template);
}

Change to this

using (MemoryStream memoryStream = new MemoryStream())
{
    using (FileStream file = new FileStream("path/to/template.xlsx", FileMode.Open, FileAccess.Read))
    {
        byte[] bytes = new byte[file.Length];
        file.Read(bytes, 0, (int)file.Length);
        memoryStream.Write(bytes, 0, (int)file.Length);
    }

    var reports = new List<NamedReport>();
    foreach (Order order in orders)
    {
        //Don't forget to reset position of memory stream.
        //otherwise all reports will have the same data
        memoryStream.Position = 0;

        //This is the optimalization
        //Open the Flexcel file from MemoryStream and thus avoid reading from disk. 
        var template = new XlsFile();
        template.Open(memoryStream);

        //Create instance of report
        var report = new FlexCelReport();

        //Populate report with variables
        report.SetValue("Order_Number", order.Code);
        report.SetValue("Order_CustomerName", order.CustomName);
        //... etc

        //Generate the report 
        report.Run(template);
    }
} //end of using memoryStream

 

Ohlédnutí za DevFestem 2014

Letošní DevFest se mi hodně líbil a oproti minulému jsem si ho mnohem více užil a méně se dozvěděl 🙂 Což bylo samozřejmě dáno tím, že jsem se tentokrát rozhodl nehonit se přednáškami a snažit se stihnout co nejvíc. Přednášek a navzájem si konkurujících akcí bylo tolik, že by se to stejně stihnout nedalo. Na některé přednášky se pak (snad) podívám ze záznamu. Vypíchnu tedy co mě zaujalo nejvíc. Je to čistě subjektivní pohled.

Co se mi hodně líbilo, tak byla bohatá nabídka doprovodného programu. Například Machine Room a Oculus Rift byla naprostá bomba. Přednášky jsou samozřejmě užitečné, ale na druhou stranu, za 45 minut se člověk nedozví nic zásadního nebo průlomového (Což je v pořádku, přednášky chápu jako inspiraci pro domácí nebo pracovní studium).  Jeden český startup (bohužel už nevím jméno) vyvinul modul, který umožňuje používat v rámci Oculus Rift i ruce. Měli připravené demo, kde si člověk mohl vlézt do srdce a nastartoval krevní oběh. Ale měli i druhé demo, kde se člověk mohl dostat až do vesmíru na oběžnou dráhu Země. To byla totální pecka, fakt úžasný pocit. Nejsilnější bylo, když jsem se na konci dema ocitl na vrcholu mrakodrapu. Měl jsem dost reálný pocit, že spadnu 🙂 Všechny svaly zaťatý, strach v očích, paráda 🙂

Z toho co jsem slyšel od ostatních lidí, tak další oblíbená atrakce byl celý Machine Room. Evidentně mají programátoři zalíbení v robotech a hračkách z Merkuru. Počítám, že pár lidí si ho pár lidí nadělí pod stromeček 🙂 Někdo vyráběl šperky ze starých klávesnic, další řídili quadrokoptéry nebo debuggoval drony. Další sexy magnet bylo svezení se novou Teslou. Mně se to bohužel nepodařilo (čti: nechtělo se mi čekat frontu), tak jsem jen sledoval jak jezdí okolo areálu. Řidič předváděl jak rychle se Tesla dostane na stovku, takže netrvalo dlouho a někdo na ně zavolal policajty 🙂 Dost dobrá také byla LARP hra – viz zde.

Jinak z přednášek se mi dost líbila “moje garáž, můj hrad” od Štěpána Bechyňského, kde ukazoval jak si postavil zařízení na detekci volného místa v garáži. Naprosto přetechnizované řešení, které zvládne asi milion garáží za 1 dolar 🙂 Šel jsem pak i na jeho workshop o tom jak si vyrobit tištěný spoj, ale nejsem elektrotechnik, takže jsem to vůbec nepobíral a v půlce odešel.

Dobrá přednáška také byla od Tomáše Holase o vlivu firemní kultury na produktivitu programátorů. Mluvil mi z duše. A dobré je, že většinu věcí o kterých mluvil, děláme správně 🙂 Takže … pokud umíš C#/Javascript/Typescript a baví tě dělat dobré weby, tak pojď pracovat k nám. Hledáme webové vývojáře.

Problem with nested forms in AngularJs

I had a long form across multiple tabs. Some parts of the form were hidden via ng-if. After some time I’ve noticed that ng-if on <form> element does not work anymore. The parts which were to be hidden, were always visible. When I’ve changed element type to <div> or <div ng-form> it worked again. WTF is happening here??

The problem was that about a week before I’ve added <form> above all those tabs and thus the <form> inside of tabs were nested. Angular has no problem with that, but browsers do. It is invalid HTML. As a result ng-if (or ng-show, ng-hide) was not even called, it was silently ignored.

So the solution is simple. If you need nested forms, always use directive ng-form instead of <form> element. Than you will have valid html and directives will be invoked.

See plunkr for demo.

RTFM 🙂

Jak se Seznam.cz (ne)stará o své uživatele

Už jsem tady jednou o Seznam.cz psal (Proč už nepoužívám Seznam.cz), a musím bohužel znovu. To, že Seznam nepoužívám, platí stále, ale moje máma potřebovala poradit s jedním mailem, do kterého se nemohla dostat. Místo obsahu mailu se ukázalo jen prázdné místo. Ukázalo se, že se jedná o rozsáhlejší problém. Mnoho lidí reportovalo, že jim zmizel obsah emailů doručených kolem 30.5. (Viz diskuze na seznamáckém fóru zde a zde). Jediná (!) reakce ze strany Seznamu je z 11.5., kde říkají, že “během několika málo dní to opraví”. Neopravili zatím nic (psáno 22.6.2014). Není ani žádné oficiální prohlášení typu “Omlouváme se za chybu, intenzivně na tom pracujeme, blablabla…”. Pokud je, tak o něm nevím. Vypadá to, že Seznam.cz situací nijak neřeší a stížnosti uživatelů ignoruje. Škoda …

Milí uživatelé, tuto zprávu ignorujte... ve skutečnosti to totiž nijak neřešíme
Milí uživatelé, tuto zprávu ignorujte… ve skutečnosti to totiž nijak neřešíme

 

Forum napoveda.seznam 2

Mlčení je asi tak ta nejhorší taktika, co Seznam.cz mohl zvolit. Zajímalo by mě proč.

Skoro to vypadá, že kazit si dobré jméno patří k filosofii Seznamu. Viz Nejhorší inovace roku 2012? Nový email od Seznamu nebo redesign Lide.cz, který v podstatě zařízl stávající službu a nahradil ji seznamkou. Spoustu lidí tím naštval, a následoval propad návštěvnosti na polovinu.  Viz článek Podarilo se Lide.cz zvrátit úbytek uživatelu? na Pooh.cz.

ceske-socnety-2014-05

 

A pro úplnost ještě tragikomický příběh o tom, jak Seznam.cz má na Firmy.cz jen jednu hvězdičku. Článek zde.

PS:  Diskuze pod profilem Seznamu na Firmy.cz je lahůdka…

 

UPDATE

Pokud máte problém se zobrazením emailů, tak nepiště na seznamácké fórum, ale kontaktujte přímo helpdesk.

Link na helpdesk:
http://napoveda.seznam.cz/cz/services/
Pak kliknout na “Přejít na technickou podporu”

Handle exceptions in ASP.NET + IIS

Handling exceptions in ASP.NET can be quite tricky. There is lot of ways how to handle them, some are described in the links below (see resources to study).

Our solution looks like this

Web.config

<system.web> <!-- MVC Settings -->
    <compilation debug="true" targetFramework="4.5.1" />
    <customErrors mode="On" /> <!-- TODO: Use RemoteOnly for production -->
  </system.web>

  <system.webServer> <!-- IIS Settings -->
    <httpErrors errorMode="Custom" existingResponse="Auto">
      <remove statusCode="404" subStatusCode="-1" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="404" path="/ErrorPages/404.aspx" responseMode="ExecuteURL" />
      <error statusCode="500" path="/ErrorPages/500.aspx" responseMode="ExecuteURL" />
    </httpErrors>
</system.webServer>

Because we need to log the exceptions for investigation we added filters. If you do not care what actually caused the exception you can skip this step, but I do not recommend it.

First you need to declare the filter (for both MVC/Http  and API Controllers. Yes that means two filters, which are almost the same)

using System.Web.Mvc;
using log4net;

namespace FinaDb.WebUI.Web
{
    public class CustomHandleErrorAttribute : HandleErrorAttribute
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(StHandleErrorAttribute));

        public override void OnException(ExceptionContext filterContext)
        {
            var controllerName = (string)filterContext.RouteData.Values["controller"];
            var actionName = (string)filterContext.RouteData.Values["action"];

            const string placeholder = "There was an error in controller '{0}' and method '{1}'";
            string message = string.Format(placeholder, controllerName, actionName);

            //Log the message for future investigation.
            //This is the whole purpose of this filter attribute
            _log.Error(message, filterContext.Exception);

            base.OnException(filterContext);
        }
    }
}

And for Web API

using System.Web.Http.Filters;
using log4net;

namespace FinaDb.Web.Api
{
    public class UnhandledApiExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            base.OnException(context);
            var log = LogManager.GetLogger(context.ActionContext.ControllerContext.ControllerDescriptor.ControllerType);
            log.Error("API error", context.Exception);
        }
    }
}

Register filter for MVC

using System.Web.Mvc;
using FinaDb.WebUI.Web;

namespace FinaDb.WebUI
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
           //That's your filter
           filters.Add(new CustomHandleErrorAttribute());
        }
    }
}

Register filter for Web API

using System.Net.Http.Formatting;
using System.Web.Http;
using FinaDb.Web.Api;

namespace FinaDb.WebUI
{
    //Shortened for brevity, you will probably want to do more, like register routes etc ... 
    public static class WebApiConfig
    {
        public static void Configure(HttpConfiguration config)
        {            
            RegisterGlobalFilters(config);
        }

        public static void RegisterGlobalFilters(HttpConfiguration config)
        {
            //That's your filter
            config.Filters.Add(new UnhandledApiExceptionAttribute());
        }
    }
}

Set appropriate status code in aspx page (otherwise 200 would be returned)

//first line in your 404 aspx page
Response.StatusCode = 404;

That’s basically all. The actual 404.aspx and 500.aspx are not shown here because they are trivial. Basically they just show some user friendly message that something went wrong. (And they look boring, not like the fancy error pages like this)

Resources to study:

http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling

https://code.google.com/p/elmah/ (I did not try that one, but it looks nice)

http://blog.dantup.com/2009/04/aspnet-mvc-handleerror-attribute-custom.html

http://benfoster.io/blog/aspnet-mvc-custom-error-pages

What to do when angular controller is initialized over and over?

It is probably a rare case, but it already happened to me at least twice.

The thing is this:

We have rather big angular application, it is more like several semi-independent applications (or modules). Everything works fine except one dialog with specific url, which causes given angular controller to initialize over and over. The browser UI is frozen, javascript engine is working like crazy, until finally page crashes. It turns out that the cause of this problem is rather silly. It is the url specified in base tag.

My buggy code looked like this

Index.html

<base href="/some/path/bleble/" />

Angular

//its typescript
($routeProvider: ng.route.IRouteProvider, $locationProvider: ng.ILocationProvider, $httpProvider: any) => {
 $locationProvider.html5Mode(true);

 $routeProvider.when("/", { templateUrl: "template.html", controller: "SomeCtrl", caseInsensitiveMatch: true });
 $routeProvider.when("/profile", { templateUrl: "template.html", controller: "SomeCtrl", caseInsensitiveMatch: true });
 $routeProvider.otherwise({ redirectTo: "/profile" });
}

Corrected version

<base href="/some/path/bleble" />

See the difference? No? .. i did not see it either. The difference is the slash “/” in the end of the base url. When the slash is present it then angular router can not find a matching url, redirects to default, fails again. So it redirects again, fails to find a match, redirects, fails …, …, over and over.

One stupid slash 🙂

Happy debugging.

Jak se mi pracuje se stolem Sit2Stand

Jedním slovem: Skvěle

Stůl je robustní, prý unese až 100kg, ale to jsem nezkoušel. Je programovatelný, takže si můžu přednastavit 3 polohy. (využívám ale jen 2 :))

Zhruba rok a pů jsem měl stůl pro práci ve stoje udělaný z papírových krabic. Nebylo to moc estetické, ale bylo to zadarmo a účel to splnilo. Nevýhodou bylo, že vždycky když jsem se chtěl posadit nebo postavit, tak jsem musel vzít notebook a přenést ho na vedlejší stůl. Což zní jako prkotina, ale pokud jsem zrovna zabraný do nějakého problému, tak poslední co chci, je přerušovat si myšlenky nějakým přesunem. Musel jsem vždycky vytáhnout notebook z dokiny, přenést, zapojit do dokiny na druhém stole, to mi samozřejmě rozházelo velikost otevřených oken, zkontrolovat že jsem vypnul zvuk aby při přenášení nezačal notebook hrát nahlas atd…

Teď když si chci sednout, tak jen zmáčknu knoflík a je to. Nepřeruší se mi flow, ve kterém práve jsem, což je velká výhoda.

Chci také tímto poděkovat svému skvělému šéfovi, že mi ten stůl koupil. Platit ho ze svého by se mi nechtělo, byť bych platit jen polovinu.

Jediná nevýhoda je absence poličky na kabely, zdroj a podobné věci. Předchozí, klasický stůl ji měl, a všechny kabely jsem do ní elegantně schoval. U sit2stand mi kabely visí a plandají. Sice jsem si je nějak svázal, ale ideální to není. Jinak všechno skvělé 🙂