Programistyczne WTF jakie Was spotkały

3

<font size="6">WTFy administracyjne.</span>

Afterthought: nie wiem czy mi się wydaje, czy ostatnio moje posty osiągają średnią długość typowego posta @bswierczynskiego. Swoją drogą ciężko było pisać tego posta spokojnie, pamiętając ile czasu zostało zmarnowane przez to co opisuje :P.

<font size="4">MySQL: pierwsza krew</span>
Z jakiegoś dziwnego powodu, podczas przenoszenia serwera zapytanie SQLowe w module mikroblogów wykonywało się w nieskończoność. Konkretnie zapytanie odpowiedzialne za polecanie podobnych mikroblogów do już obserwowanych.

Co dziwne, bo dokładnie to samo zapytanie na dokładnie tej samej wersji SQL na poprzednim serwerze wykonywało się ~~0.3 sekundy.
Więc próbujemy debugować, wklejamy to zapytanie do konsoli mysqlowej:

SELECT t1.*, GROUP_CONCAT(skill_name ORDER BY skill_order) AS skills
FROM (
        SELECT user.user_id, user.user_name, user_photo, user_bio, COUNT(uf1.follower_id) AS followers
        FROM `user`
        LEFT JOIN user_follower uf1 ON uf1.user_id = user.user_id
        WHERE user.user_id IN(SELECT microblog_user FROM microblog WHERE microblog_parent IS NULL GROUP BY microblog_user)
        GROUP BY user.user_id
        ORDER BY followers) AS t1
JOIN user_skill ON skill_user = t1.user_id
LEFT JOIN user_follower uf2 ON uf2.follower_id = 37200 AND uf2.user_id = t1.user_id
WHERE uf2.user_id IS NULL AND t1.user_id != 37200
GROUP BY skill_user
ORDER BY RAND()
LIMIT 5;

Czas wykonania: nieskończoność (ok, czekałem tylko kilka minut).

Dlaczego? Zapytajmy MySQL!

EXPLAIN SELECT t1.*, GROUP_CONCAT(skill_name ORDER BY skill_order) AS skills
FROM (
        SELECT user.user_id, user.user_name, user_photo, user_bio, COUNT(uf1.follower_id) AS followers
        FROM `user`
        LEFT JOIN user_follower uf1 ON uf1.user_id = user.user_id
        WHERE user.user_id IN(SELECT microblog_user FROM microblog WHERE microblog_parent IS NULL GROUP BY microblog_user)
        GROUP BY user.user_id
        ORDER BY followers) AS t1
JOIN user_skill ON skill_user = t1.user_id
LEFT JOIN user_follower uf2 ON uf2.follower_id = 37200 AND uf2.user_id = t1.user_id
WHERE uf2.user_id IS NULL AND t1.user_id != 37200
GROUP BY skill_user
ORDER BY RAND()
LIMIT 5;

Czas wykonania: nieskończoność.
Tak, EXPLAIN wykonuje się nieskończona ilość czasu. Jeśli mysql nie potrafi nawet ułożyć planu zapytania, to prawdopodobnie samego zapytania szybko nie wykona ;).

No to co, upraszczamy zapytanie.

EXPLAIN SELECT t1.*
FROM (
    SELECT user.user_id
    FROM `user`
    LEFT JOIN user_follower uf1 ON uf1.user_id = user.user_id
    WHERE user.user_id IN(SELECT microblog_user FROM microblog WHERE microblog_parent IS NULL GROUP BY microblog_user)) AS t1;

Czas wykonania: nieskończoność.
Tak, EXPLAIN takiego prostego zapytania wykonuje się nieskończona ilość czasu.

Ale:

EXPLAIN SELECT user.user_id
    FROM `user`
    LEFT JOIN user_follower uf1 ON uf1.user_id = user.user_id
    WHERE user.user_id IN(SELECT microblog_user FROM microblog WHERE microblog_parent IS NULL GROUP BY microblog_user)

Czas wykonania: natychmiastowo.

Czyli EXPLAIN SELECT * FROM (X) powoduje timeout, ale samo X już nie.

Co jeszcze ciekawsze, jeśli w timeoutującym zapytaniu:

  • usunąć WHERE IS NULL
  • albo zamienić (SELECT microblog_user FROM microblog WHERE microblog_parent IS NULL GROUP BY microblog_user) na (SELECT DISTINCT microblog_user FROM microblog WHERE microblog_parent IS NULL)

Wszystko działa błyskawicznie.

Nie mieliśmy siły (z @Adam Boduch) walczyć z mysqlem.
Rozwiązanie problemu: usunięcie feature polecanych mikroblogów ;). Nikt tego nawet nie zauważył więc pomysł uznaję za dobry.

<font size="4">iptables.up</span>

A to z kolei psuło krew @Revowi. Napisaliśmy sobie mały skrypt automatycznie wykonujący pewne operacje na iptables. Jest 24 marca, godzina 23:25

rev napisał(a)

[2015-03-24 2302] iptables.up -> /etc/iptables.up

rev napisał(a)

[2015-03-24 2317]
teraz zróbmy sztuczkę
i wykonajmy reboot
zobaczymy co domyślnie wstanie

I skrypt ten się nie wykonał:

rev napisał(a)

[2015-03-25 2242] po prostu w ogóle iptables.up nie zawołało się przy eth0 up

rev napisał(a)

[2015-03-29 2211] ani nie wywołuje /etc/iptables.up ani nie dodaje tej route'y

Rozpoczynamy debugowanie, bo kiedyś trzeba:

rev napisał(a)

[2015-04-17 2005] do /etc/iptables.up dodałem echo date >> /root/iptables-log na koniec

rev napisał(a)

[2015-04-17 2033] root@4p ~ # cat iptables-log
pusto :/

rev napisał(a)

[2015-04-17 2222] nie utworzył /root/iptables_stdout

rev napisał(a)

[2015-04-17 2222] root@4p ~ # /etc/iptables.up
root@4p ~ # cat iptables_stdout
root@4p ~ #

I rozwiązanie problemu (o pierwszej w nocy): z dokumentacji run-parts (wykorzystywane przez runnera tego czegoś):

If the −−lsbsysinit option is not given then the names must consist entirely of upper and lower case letters, digits, underscores, and hyphens.

Kto to wymyślił. Jeśli do run-parts nie zostanie przekazany parametr --lsbsysinit, to po cichu ignoruje każdy plik z kropką gdziekolwiek w nazwie.
Nie potrafię oddać jak bardzo absurdalne to jest (albo było, o 1 w nocy po 4 godzinach szukania błędu). Równie dobrze mógłby ignorować pliki zaczynające się na 'a', o ile nie dostanie parametru --donotignore.

A co robi opcja --lsbsysinit? Ustala jeszcze fajniejsze zasady!

If the --lsbsysinit option is given, then the names must not end in
.dpkg-old or .dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong to
one or more of the following namespaces: the LANANA-assigned namespace
(^[a-z0-9]+$); the LSB hierarchical and reserved namespaces
(^?([a-z0-9.]+-)+[a-z0-9]+$); and the Debian cron script namespace
(^[a-z0-9][a-z0-9-]*$).

Poważnie, co to za program, kto to wymyślił :P.

http://manpages.ubuntu.com/manpages/gutsy/man8/run-parts.8.html

(Nie tylko my się nacieliśmy - http://askubuntu.com/questions/406126/why-is-ifup-not-running-all-of-the-if-pre-up-d-scripts)

<font size="4">MySQL powraca</span>

Na koniec honorable mention dla mysqla:

  1. apt-get upgrade mysqla się nie udaje i rzuca błędami. Usługa mysqla przestaje odpowiadać na jakiekolwiek prośby i groźby.
  2. z braku innej opcji trzeba ubić proces
  3. po restarcie serwera container lxc z mysqlem w ogóle odmawia posłuszeństwa, i nie chce sie podnieść żadnym sposobem (tylko container z mysql, na 9 containerów łącznie).
  4. stworzyliśmy nowy container i skopiowaliśmy dane mysqla tam wszystkie. Dokładnie ta sama wersja mysqla, etc. Niestety, mysql nie zamierza ich wczytać, bo upiera się że dane są uszkodzone nienaprawialnie, kompletnie bezwartościowe i ogólnie FUBAR'd.
  5. Tak, jedno upgrade i zabicie procesu mysql kompletnie zniszczyło 10 GB danych (oraz cały system przy okazji).
  6. dobrze że mieliśmy świeży backup, bo inaczej trzeba by pisać posty od zera ;).

Nie wiem czy tylko ja mam takie problemy z mysql (inni jakoś z nim żyją i nawet lubią chyba). W każdym razie od tego momentu boję się go dotykać :P.

1

Korzystam z aplikacji Messanger facebooka na telefonie. Dzisiaj zmieniłem hasło, ii przy próbie uruchomienia apki dostaję komunikat "Sejsa wygasła. Zaloguj się ponownie", klikam OK, myślę zaloguję się i będzie git.

"Wylogowywanie..."

Bam.

"Sesja wygasła. Zaloguj się ponownie". I tak w kółko. Restart apki nie pomaga. Reinstall apki nie pomaga :| Przywrócenie starego hasła nie pomaga (w sumie czemu miałoby, ale byłem zdesperowany). Nawet nie wiem czy jestem ciągle zalogowany czy nie.

12

b1e8e7fe2d.png

0

Moze mi ktos wytlumaczyc dlaczego tak?

Pracuje obecnie w embedded. Urzadzenie nie ma twardego dysku wiec nie moze nigdzie nic zapisac/odczytac. Ale nadal to nie wyjasnia jednej rzeczy

Jest 15 plikow SearchTableXX.c Gdzie XX to numer. jest 00 jest 10 jest 61 jest 99.

Porownalem plik 60 z 61. przynajmniej 60% jest takie same. Wiec patrze dalej... a roznica jest tylko w danych!
Tak czasami jest
0, 0, 0, 0, 0
a czasami
0, 1, 0, 1, 0

Kazdy plik ma dokladnie te same metody, jedynie co sie rozni to zestaw danych.

1

Nie ma to jak dobrze nadane nazwy properties.

0

Apropos dzisiejszej debaty : www.mamprawowiedziec.pl czyli strona podana przez kandydata podobno zawiesiła się niemal natychmiastowo :D i nie działa do teraz

9

Bug który denerwował od kilku tygodni przestał się reprodukować akurat dnia, w którym postanowiłem się za niego zabrać.

8

przegladam kod w obecnej pracy i widze takie cos

void hack_interesting() 

ehh a oni nadal twierdza ze code review nie jest potrzebne...

14

W ramach tego artykułu (błąd w systemie PKP Intercity umożliwiający przejazdy za darmo) - kod źródłowy JSów do stronki zakupu biletów na przejazdy pekape intersiti:
https://bilet.intercity.pl/irez/js/irez.js

W tym kodzie jest wszystko: od getStationNameByIbnr, po sprTylkoLiteryICyfry.

Bonus:

komentarz na Niebezpiecznik.pl napisał(a)

Najbardziej mi się podoba skrupulatność przy upewnianiu się, czy w ciągu nie występuje czwórka i bardzo liberalne podejście do szóstki:

(…) && wyraz.charAt(i) != “3” && wyraz.charAt(i) != “4” && wyraz.charAt(i) != “4” && wyraz.charAt(i) != “5” && wyraz.charAt(i) != “7” && wyraz.charAt(i) != “8” && (…)

7

W robocie piszemy bibliotekę dla programistów gier. Dokumentujemy ją dość skrupulatnie poza tym standardowy use case jest podany "na tacy". No ale to nie wystarcza ; < Nie ma tygodnia żebyśmy nie dostali maila od jakiś magika, który:

  1. Nie czyta dokumentacji i dziwi się, że mu nie działa
  2. Czyta dokumentację bez zrozumienia i dziwi się, że mu nie działa
  3. Czyta dokumentację ale i tak robi po swojemu i dziwi się, że mu nie działa
  4. Miesza runtimy i dziwi się, że mu nie działa
  5. Nie zna podstaw C++/C# i dziwi się, że mu nie działa
  6. Pisze swój kod w oparciu o UB i dziwi się, że mu nie działa

Bardzo rzadko dostajemy zgłoszenia o faktycznych bugach w naszej bibliotece (a jak podeślą nam core dumpa to w ogóle mamy święto ; > ).
Konkluzja, nie tylko newbie na tym forum nie czytają dokumentacji ; /

13

WTF z dzisiaj. Dostaje taska żeby popatrzeć na pewien skrypt pythonowy który ponoć ślimaczy się dla dużych plików wejściowych (XML). Sugestia jest taka że to pewnie minidom zamula i może warto użyć innej biblioteki. Co mówi profiler? Że getElementsByTagName jest wołane kilkadziesiąt milionów razy. Co widzę w kodzie? 3 linijki odpowiedzialne za usunięcie danych z pewnej sekcji pliku XML:

header_end = int(table.getAttribute("ss:HeaderEnd"))
while len(table.getElementsByTagName("Row")) > header_end:
    table.removeChild(table.getElementsByTagName("Row")[header_end])

Warto wspomnieć że getElementsByTagName musi przelecieć przez wszystkie dzieci danego elementu żeby je odszukać...

Edit: dla jasności, ten kod przegląda XMLa żeby znaleźć wszystkie elementy Row, jeśli nadal jest ich za dużo to znów przegląda XMLa żeby znaleźć wszystkie elementy Row, usuwa jeden i powtarza cały proces od nowa.

Więc jeśli Rowów było do usunięcia 10 to najpierw przeglądamy 2 razy 10 elementów, potem 2 razy 9 elementów potem... czyli O(2*n2) podczas gdy w rzeczywistości można O(n).

12

Opowieści ciąg dalszy :D Lead powiedział żebym spróbował ten pythonowy kod troche ogarnąć bo "jakby co" to my go niestety supportujemy. O tym że mam przed sobą plik na 4k linii ze zmiennymi globalnymi i bez jednej klasy to nawet nie wspominam, ot życie ;] Ale z ciekawostek:

  • Ziomek, nie wiedząc czemu, napisał własny "logger", gorszy od najgorszego loggera ;] Nie zrobił żadnego enuma do rozpoznawania poziomu logowania. Po prostu na pałe dokleja zawsze jeden z globalnych stringów z prefixami, a potem ten jego logger robi drabinkę takich oto cudów:
    if message.startswith(DEBUG_PREFIX):
        if not globals()["DEBUG_MODE"]:
            flagPrintMessage = False
        pMessage = "[DEBUG] " + message[6:]
    if pMessage.startswith(WARNING_PREFIX):
        if globals()["NO_WARNING"]:
            flagPrintMessage = False
        pMessage = "[WARNING] " + message[8:]
...

Dostanę raka oczu od patrzenia na to ;] I żeby ktoś nie miał wątpliwości, ten kod powstał dużo później niż dodano do pythona pakiet logging...

  • Gość miał jakąś awersje do tworzenia nowych metod. Są tu takie po ~1k linii kodu. Co ciekawe chyba zauważył że źle mu sie to czyta ale zamiast podzielic na metody wstawiał w kodzie takie oto ramki:

=============================================

#  CREATE A LIST WITH PLUGINS TO USE AND ASSOCIATED DATA
# =============================================

cośtam cośtam...
# =============================================
# READ DATA USING THE APPROPRIATE PLUG-IN
# =============================================
cośtam cośtam

Przynajmniej jest mi łatwiej wyszukać miejsca gdzie trzeba zrobić extract-method ;]

edit: Widzę w historii commitów że robił jakiś "code refactoring". W opisie taska na jirze widnieją ładne rzeczy -> sensowne nazwy dla zmiennych, podzielenie funkcji na mniejsze, wydzielenie klas, unit testy. A co widzę w zmianach podczepionych pod tego taska? Zmianę w nazwach zmiennych w stylu pluginName -> plgName. Powoli zaczynam podejrzewać że ten gość to jakiś troll był i on tak celowo... ;]

5

Podczas analizowania kodu związanego z działaniem wielowątkowości i asynchroniczności w .NET:

#undef SleepEx
status = SleepEx(0,TRUE);    
#define SleepEx(a,b) Dont_Use_SleepEx(a,b)

https://github.com/dotnet/coreclr/blob/4cf8a6b082d9bb1789facd996d8265d3908757b2/src/vm/win32threadpool.cpp#L2980
Pierwszy hack miał na celu zablokowanie użycia SleepEx, ale później się jednak okazało, że w kilku miejscach trzeba go użyć i nic sensownego nie chciało im się już z tym robić ;).

0

Kiedyś, jak moja siostra była na studiach to dostali zadanie w grupie: narysuj choinkę korzystając w pętli i z funkcji printf. Wiadomo takie tam standardowe zadanie w C. No i siedzi ta moja siostra i pisze te pętle i pisze i pisze, a ja się pytam "Co Ty tam robisz?" No to ona mi na to, że zadanie mają na studiach, że taką choineczkę mają narysować :) No to ja mówię, że to chyba łatwe jest prawda? Po tym wszystkim zapytała: "A Ty umiesz?" No to odpowiedziałem: "Pewnie!"

Hehe to pokaż:

#include <stdio.h>

int main(){
    printf("    *    \n");
    printf("   ***   \n");
    printf("  *****  \n");
    printf(" ******* \n");
    printf("*********\n");
    printf("   ***   \n");
    return 0;
}

Naturalnie g**no znałem się na programowaniu jak tylko w basicu input i print umiałem, a to samo w C :P

8

Kod ma za zadanie wylosować datę urodzenia. W kodzie ręcznie wpisane tabele:

new Array(
'01 ',
'02 ',
'03 ',
'04 ',
'05 ',
'06 ',
'07 ',
'08 ',
'09 ',
'10',
'11',
'12',
// itd. aż do 30
)

Tak samo z miesiącami (także zapisane cyframi) i latami.

6

zasada ograniczonego zaufania wobec generatora identifykatorow (useId to hash z identyfikatorami w uzyciu):

public int GetNewUniqueId(UniqueIdGenerator g)
{
    int cnt = 0;
    int newId = 0;
    while(cnt < 15)
    {
        newId = g.GenerateNewUniqueId();
        if(newId != 0 && !useId.Contains(newId)) { cnt = 15; useId.Add(newId); }
        cnt++;
        
    }
    if(newId != 0) return newId;
    else return -1;
}
7

Przyszedl Project Leader.

Mowi czy moglbym zrobic jakis dokument na temat jak unikac bledow w C++.
Ja sie pytam "ale, ze jak, ze co?"
"No bo byl blad bo zmienna byla nie zainicjalizowana" (w c++ jak sie nie zainicializuje zmiennej to ma "randomowa" wartosc co wie chyba kazdy programista C/C++)
"aaahaa... oookeeej moge zrobic"

Nie, nie pisal to zadnej stazysta/junior. W firmie sa sami "seniorzy".

Na moja rade
"to czemu nie sprawdzane sa warningi, a IDE nie jest ustawione tak by krzyczalo o tym? No i co z Code-review? Dzieki temu kod bedzie duzo lepszej jakosci i nie bedzie takich bledow"
"no wlasnie jakbys mogl napisac taki dokument ze trzeba usuwac warningi... a code review zabierze za duzo czasu"

No tak... bo debugowanie przez X dni glupiego problemu nie bierze WCALE czasu...

1

Asynchroniczne przetwarzanie plików excela. Kolega stwierdził, że to zrobi i będzie śmigało na wątkach i będzie super. Podpowiedziałem, żeby użył @Async na metodzie przetwarzającej, bo w ten sposób zrobi część biznesową, a technikaliami zajmie się spring... Poniżej efekt prac:

        @Async
public Future<Boolean> uploadAllWorkingDocumentsForReportGeneration(byte[] workingDocument, Long reports, Long userId) throws ParseException {
    if (processingReportNumber != null) {
        throw new IllegalStateException("Processing is busy. Please wait until its finished. Current processing report number is: " + processingReportNumber.get());
    }

    ///... walidacje parametrów
    // Reset counter and apply "lock"
    logger.info("Start processing multiple reports upload");
    processingReportNumber = new AtomicInteger(0);

    for (Report report : reports.getReports()) {

        processingReportNumber.addAndGet(1);
        logger.info("Processing report number " + processingReportNumber.get() + " with id " + report.getReportId());
// okreslanie sheet name i innych takich
        logger.info("Fetching sheet: " + sheetName);

        Workbook singleWorkbook = createWorkbookFromExcelSheetByReport(workingDocument, sheetName);
        // trochę kodu nieistotnego dla nas pobiera dodatkowe dane dla parsera
        for (RCG rcg: rcgs ) {
               documentParser.parse(report, user, rcg, singleWorkbook);
        }
    }
    // Release "lock"
    logger.info("Multiple reports processing finished");
    processingReportNumber = null;
    return new AsyncResult<>(true);
}

metoda oczywiście wykona się w osobnym wątku, ale po pierwsze będzie można ją tylko odpalić raz na system co oznacza, że dwóch userów nie będzie mogło na raz parsować swoich arkuszy. po drugie samo procesowanie nadal jest jednowątkowe i jak trwało godzinę tak będzie trwać godzinę...

// edit: kod został jedynie pozbawiony elementów pozwalających na łatwe odgadnięcie do czego służy. Wyciąłem też nieznaczące elementy, które swoją drogą nie powinny tam być, ale to inna bajka...

0

@Koziołek czy to jest kod żywcem wyjęty z kontrolera/serwisu czy go przerobiłeś ? jeżeli nie, to dlaczego kolega w czymś co może być wywołane z wielu wątków robi:

dzikiego locka, bo co to jest ???

///... walidacje parametrów
    // Reset counter and apply "lock"
    logger.info("Start processing multiple reports upload");
    processingReportNumber = new AtomicInteger(0);

przecież to jest podręcznikowy race condition...

0

Kochany Javascript :)
W komentarzu rezultat wyświetlony w przeglądarce:

alert(true&&null&&true); //null
alert(true&&0&&true);	 //0
alert(true&&1&&true);	 //true

Jest na to jakieś sensowne wytłumaczenie?
Tzn. nie zmienia to niby tak dużo, ale jeżeli ktoś dalej da result != resultOfSthElse, to ciężko to wychwycić...

1

jQuery validation, uznaje 123,456.781 za liczbę, ale jednocześnie twierdzi, że jest ona mniejsza niż 1.

// http://jqueryvalidation.org/number-method/
number: function( value, element ) {
	return this.optional( element ) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
},
// http://jqueryvalidation.org/range-method/
range: function( value, element, param ) {
	return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
},

Czemu w jednym przypadku uznają przecinki jako separator tysięczny, a w drugim o tym zapomnieli?

1

Nie wiem co o tym myśleć.
rly.png

12

Jest sobie pewne forum internetowe (nie mogę napisać jakie) z funkcją raportowania. Moderator na podglądzie zgłoszonego raportu widzi:

  1. Id
  2. link do zgłaszanego posta
  3. treść raportu
  4. nazwę użytkownika zgłaszającego raport - jest ona jednocześnie linkiem do profilu tego użytkownika
  5. adres IP użytkownika zgłaszającego raport - jest on jednocześnie linkiem do jego zbanowania. (Jego - zgłaszającego raport, nie autora postu.)
0
    if (rc) and (TotalDoc>0) then
    begin
      //!!!!!!!!!!!!!!!!!!!!!pętla prawdopodobnie do usunięcia!!!!!!!!!!!!!!!!!!
      For i:=0 to impStat.Count-1 do
      begin
        isi:=impStat.ImpStat[i];
        STOO.Caption:='Tworzenie raportu importu';
        EDate:=Now;
        Desc:='1'+#13#10;
        Desc:=Desc+' Import dokument/oddział :  '+ImpData.ImpDocTypeName+' / '+ImpData.ImpOddzialNr+#13#10;
        Desc:=Desc+' Data zbiorów            :  '+DateToStr(ImpData.ImpDate)+#13#10 ;
        Desc:=Desc+' Zbiór                   :  '+ImpData.ImpNAme+#13#10 ;
        Desc:=Desc+' Początek / koniec       :  '+DateTimeToStr(SDate)+' / '+DateTimeToStr(EDate)+#13#10;
        Desc:=Desc+' Dokumentów łącznie      :  '+Format('%0.6d',[isi.TotalDoc])+#13#10;
        Desc:=Desc+' Stron łącznie           :  '+Format('%0.6d',[isi.TotalPages])+#13#10;
        Desc:=Desc+' Dokumentów poprawnych   :  '+Format('%0.6d',[isi.ValidDoc])+#13#10;
        Desc:=Desc+' Dokumentów błędnych     :  '+Format('%0.6d',[isi.InValidDoc])+#13#10;
      end;
      if not rc then
         Writeln( lgo.FileHandle^,Desc);

(...)

end; 

No ale chociaż jest komentarz, że do usunięcia.

Edycja: Komentarz dopisał później ktoś inny, przy przeglądaniu kodu.

0

@TomRiddle
Chodziło mi o to, że wg. googla 10%+10%+100 != 100+10%+10%
Tzn wyniki z linków 2 i 3 są różne.

7

Działanie google nie jest WTF-kiem, a wynika ze sposobu ewaluacji i późniejszej interpretacji wyrażeń w języku słabotypowanym. Podobnie jak w Javascript. Problemem jest, podobnie jak w Javascript, nasza nielogiczna intuicja, która wychodzi ze szkolnych regułek o przemienności działań, ale ignoruje różnice typów w operandach. Inaczej mówiąc w czasie nauki przyswoiliśmy sobie, że dodawanie jest przemienne, konwersja typów zmiennoprzecinkowych (ułamków) i całkowitych robiona jest przez nas w locie, a jednocześnie ignorujemy inne typy w działaniach np. procenty albo, czego też byłem świadkiem, waluty.

I, żeby nie było, że post bez WTF-ka spłodziłem...

public class UploadedReport{

    //... różne pola m.in. to
    @ManyToOne
    @JoinColumn(/*....*/)
    private Blob blob;
}

Klasa Blob to jest nasza klasa, która w środku ma kolekcję raportów do których się odwołuje. W ramach jednego bloba możemy mieć wiele raportów więc mapowanie wygląda jak wygląda. Generalnie wszystko jest OK, bo klient chce mieć te bloby w swoim systemie od razu (by wyglądało, że pobieranie jest szybkie)...

Ruszamy na produkcji i zgłoszenie od klienta "ekran z UploadedReport nie działa". Rzucamy okiem do loga i tam OutOfMemory... WTF??? @ManyToOne jest Eager, ale takie było wymaganie, żeby odsyłać od całą listę z blobami...

Rozwiązanie zagadki:

  1. Stacja deweloperska ma na serwer 4GB RAM
  2. Środowisko testowe ma 1GB RAM na apkę.
  3. Produkcja ma 512MB RAM na całość....

Terminator w kinach, Dragonball w kinach i serwer ma 512MB RAM... który mamy rok?

5

paczcie co znalazłem

if (imageURL == null) {
    try {
      throw new IOException("Resource not found: " + path);
    } catch (IOException ex) {
      ex.printStackTrace();
    }
} else {
    return (new ImageIcon(imageURL, description)).getImage();
}

2 użytkowników online, w tym zalogowanych: 1, gości: 1