Day Four to Six: Osaka/Kyoto (Arashiyama, Tenryu-ji Temple, Dōtonbori)

After Gamcheon, we stopped by the hotel to pick up our luggage and headed to the Busan international airport. We arrived in Osaka close to 10. Most restaurants are closed, so we asked folks at the front-desk about where to get food at that hour, and they recommended the restaurant right in front of the hotel. It looked good, but I couldn’t really place an order because no one at the restaurant spoke English. So…., it came down to the most basic form of communications – pointing at pictures. We got Okonomiyaki, Takoyaki, and some dish I don’t know what’s called. They were yummy!

restaurant Food

The next day, we headed to Kyoto via bullet train to visit Arashiyama.

Arashiyama Bamboo Grove

I wanted the kids to have a chance to take a bullet train from Osaka, so I picked Kyoto, which is about 12 minutes via a bullet train. And when in Kyoto, you have to go to Arashiyama Bamboo Grove, which is probably the most iconic place in Kyoto. I’ve looked at photos online, and it looked serene with bamboos all around like below.

Arashiyama EARLY IN THE MORNING

However, when I got there, there was nothing serene about the place. There were just way too many people. We moved along with tons of people. Later I found out that you have to go really early in the morning to have the place all to yourself.

bamboos next to bamboos

Tenryu-ji Temple

After a short stay, we went to Tenryu-ji Temple, which was right next to Arashiyama. It was a nice temple, and just like Arashiyama, it was crowded too.

old painting side pond

Subway

When we first arrived, we really had hard time figuring things out. Japanese subway systems are huge and complex, and Osaka stations (there are two because of two different lines, but their respective stations are close but not the same building.) are HUGE. But once we figured out, buying tickets was a breeze.

Other photos of Japan

Police car
alley 1
alley 2
old house

Post to Twitter

Day Three: Busan (Gamcheon Culture Village)

When we were done with dinner in Gyeongju, we took a train back to Busan and to our hotel. We were beat, so I think all of us had a good night.

I woke up early on this day and took a walk outside to go to McDonald to get some breakfast. There were A LOT of bars and restaurants along the way to the McDonalds. It looked the area surrounding the hotel is pretty happening place.

Street 1
Street 2

After breakfast, we packed out stuff, checked out, and left our bags at the front desk so that we can go to the Gamcheon Culture Village before heading over to Osaka, Japan.

Gamcheon Culture Village is known for narrow streets and steps, and public arts. It’s built on a hill, so it’s better to go to the top and walk down. There are helpful signs throughout, so it’s easy to find your way around. Here are some photos, but for all, you can visit my album.

overview Big fish Cat mural ![Creepy birds][8] little prince Book steps Narrow steps

Post to Twitter

Trip to Korea and Japan

I recently took a trip to Korea and Japan with my two teenage kids. It had been 14 years since I left Korea after leaving Samsung, and at the time my oldest was three-years-old.

I had basic itinerary for each day, and it turned out to be quite ambitious. We ended up doing one or at most two things on the itinerary, and it was good.

One thing kids complained the most was the amount of walking. Even when you take taxis everywhere, you will end up walking a lot, so you should make sure to wear comfortable walking shoes.

The followings are itineraries. Click on a link below to see specific post.

Pre-paid SIM card

One thing that I regret not getting in Korea was pre-paid SIM card. I have T-Mobile in the US, and my plan allowed unlimited data and text in both Korea and Japan, but only at 2G speed. It was SOOOOOOOO slow. Don’t make the same mistake.

Where do you get a pre-paid SIM card?

The easiest place to get it is at the airport.

If you didn’t get one at the airport, you can also get one at a convenience store (like GS25, 7-11, or CU). However, not all of them will carry one. And the clerks there didn’t understand pre-paid SIM card. Ask for “USIM” (Universal SIM) card. The only place I was able to find was in Gangnam area.

Another place to get one is at a carrier store (like KT). However, you can only buy it at a carrier store, not at an authorized reseller. There are a lot more resellers than carrier stores, and it was very confusing to me which was which.

Best bet is at the airport. Just get one at the airport.

Post to Twitter

Day Two: Gyeongju (Bulguksa)

On the day two, I planned to take a bullet train down to Busan, check into our hotel, and travel to Gyeongju (old capital city of Korea and about 30 minutes trip from Busan). However, when we arrived at Busan, I decided to store our luggage in a locker in Busan station and go straight to Gyeongju, instead of checking into the hotel first to save time.

KTX

KTX operates the bullet train in Korea. It takes around three hours (as opposed to 5+ hours) to go from Seoul to Busan on one of the bullet trains. And it’s comfortable, quiet and some window seats do come with USB ports and power outlet. It cost around $50 per person for one way ticket, so it wasn’t the cheapest. But it’s an experience, so I was willing to pay.

However, their English site SUCKS. OMG. It sucks big time.

As you can see, there is quite a bit of information missing from English page (like being able to select your seats and showing extra stations it will be stopping at). It is a bit cheaper and takes a bit longer if they stop at additional cities (stations).

Gyeongju

A KTX bullet train to Gyeongju from Busan takes only 30 minutes, but the major downside is that its station in Gyeongju is different from old station, and it’s quite far from the city and the major attractions. You can take a bus to the city from the station, but it departs every hour and takes too long. We are on a vacation, so I was willing to spend money on taxi ride. It’s even further to the Bulguksa temple we were trying to go.

Seokguram

After we arrived at the station, I went over to the taxi stand and got in the first taxi there. An old man was driving, and when he heard that we were going to Bulguksa, he suggested that we go to Seokguram first since it’s close to Bulguksa and it’s up high in the mountain, it’s easy to see it and walk down the mountain to go to Bulguksa. I’ve been to Seokguram before, but that was more than 15 years ago, so I obviously couldn’t remember what it was exactly. He told me that going there will only 10+ minutes, but it didn’t hit me that it would also increase the taxi fare. I honestly couldn’t tell whether the taxi driver was trying to scam us for more taxi fare or genuinely trying to help us get the most of the trip. And since it was around 3-ish and Bulguksa closes at 6, he drove like a maniac.

After entering a small structure where Seokguram is, I realized what it was. It’s a stone Buddha statue what was carved inside a rock, and it’s inside the the small structure in the photo above. Taking a photo inside was prohibited, so I couldn’t take a photo. There was also a small desk inside where a person was collecting dontation. You write your wish on a what looked like a guestbook, pay like $50, and they place it inside the cave next to the Buddha statue. I was like, how does that make wish come true? Another over-commercialization. Boo.

In the entrance of path way to Seokguram, there was a huge bell they let you ring for $1 donation, so of course, I went and rang it. You can see the video here.

Bulguksa

At the bottom of Seokguram is one of the most popular buddhist temples in Korea and has many National Treasures in display. Because it was close to Buddha’s birthday, they had colorful lanterns hung in the sky. Most of them had a piece of paper with names attached to them. I thought it would be cool to also put our names on there. But, when I approached a booth to ask how I could do it, they gave a few options and told me that more expensive ones were supposed to bring better/more luck. Sure, I suppose they have to make somehow and it probably costs money to hang all those lanterns, but I was appalled at selling “luck”. It just gave me bad taste in my mouth, so we decided not to do it.

There was a brass pig, and rubbing it is supposed to bring good luck, so we rubbed the hell of it. Look how shiny it is!

brass pig

But the place was beautiful and luckily there weren’t many people in the temple.

Roof

Warriors

Fish

Lanterns

Bridge

Smaller bridge

Traditional Korean dinner

After Bulguksa, we took a cab to a dinner place. In places Gyeongju, they have many restaurants that serve you traditional dinner – on a gigantic table.

Menu 1 Menu 2


Post to Twitter

Introducing LISTORIO!

It truly has been a while since I posted anything. Last post was in 2018!

Today, I would like to introduce a new project I created, Listorio

Variation of this project has been in my head probably since early 2000’s, when Internet popularity exploded (and businesses imploded). I’ve always wanted to create my list of anything, and put it out there in the internet to be found and shared.

I just had this rush of wanting to create something, and this idea came back to me, so I spent about two weeks after working hours to create it. It does everything I want, so the next is to create a lot of my own lists and share them. I will try to market it different ways here and there, so I could test whether it’s something people want (like Y Combinator‘s motto – Make something people want). I am a person, so it should count! :D

Here are some lists that I had created.

Post to Twitter

Day One: Seoul (Gyeongbokgung, Insa-dong, Bukchon Hanok Village)

First few days after arriving in Korea were spent meeting different relatives. After the obligatory meet and greets with relatives, we were able to go off on our own and explore.

Gyeongbokgung, Insa-dong, Bukchon Hanok Village are all located closed to each other (inside the red square), so it can easily be done in a day. It’s on the north side of Seoul (north of Han River). You can see Gangnam at the lower right side of the map.

Makers Hotel

I booked this hotel because it looked really cute, had three beds (one twin and one bunk bed with two twins), close to places we wanted to visit. I booked all hotels with Chase Sapphire Reserve points on their points award site, which lacked good user experience. I had to go between the site and TripAdvisor site to make sure I wasn’t booking a roach motel. Nevertheless, it was a good choice. While the room was super tiny, we were only there to mostly sleep, it didn’t matter much. Location was perfect. Kids liked it too.

FourB Roastery (Bagel place)

The hotel had breakfast buffet for about $10 per person, but it really didn’t look that good. So, I used MangoPlate app to find bakeries/cafes around my location (the app didn’t have breakfast category) and looked for ones that are open early in the morning. Interestingly most bakeries/cafes do not open until lunch time. :( FourB had good rating and it was on our way to Gyeongbokgung, so we stopped by here for breakfast.

OMG. The bagels were phenomenal. As you can see in the photo, they bake their own bagels on the site. And those bagel makers (I don’t know what to call them really) wear chef hat and shirt!!!! Koreans always tend to take things to the extreme. Anyhow, it was very good and it was a good way to start the day. :)

Gyeongbokgung

We totally lucked out when we got there. It was around 11AM, and we were just in time to catch the change of the guard. You can actually see the whole video here. Even though it was Monday, it was packed.

You can see in the photo above that there are many people wearing traditional Korean dresses (한복, hanbok). You can rent them near the palace, and admission to the palace is free if you wear a traditional dress. Admission fee is around $6, so it’s not too bad if you have to pay the fee. We of course didn’t rent the traditional dress.

The palace covers a lot of ground, so I would recommend you wear a comfortable walking shoes.

Insa-dong

This is a cool place to visit as a visitor to Korea because it’s filled with stores that sell souvenirs. I didn’t take any pictures, but I have a short video of our walk through the area here. We walked through here to get to Bukchon Hanok Village.

Bukchon Hanok Village

This is the first place I felt disappointed. It was supposed to be a small village of old style houses, but there weren’t whole lot of houses and it was full of tourists. The number of tourists shouldn’t have surprised me, but still, it totally ruined the whole experience. Not only that, because kids were really tired of walking and they were complaining a lot, we stopped by a nice looking tea cafe and ordered their desserts, but the owner told me that I also had to order a tea. I would have said that’s a bullshit and left, but since kids were complaining too much about walking too much, I said whatever and paid for a cup of tea. I guess it shows the over-commercialization of the area. Oh, well.

While kids stayed at the cafe, I took a walk through the village, which I wasn’t too impressed with. We ended the day soon after. I planned to visit more places, but I had to end the day earlier because of kids’ complaints. Oh, well. The life of a parent. :D

Post to Twitter

When JSON encoding does not play well with character encoding

There comes a time for a developer to face a bug so weird that it leaves him/her speechless and scramble to find an answer wherever possible.

After seemingly innocent deployment to production, I noticed huge spike in errors like the following:

ActionView::Template::Error: "\xEB" from ASCII-8BIT to UTF-8

Offending line was JSON encoding of geo location information provided in request header by our cache provider. \xEB happens to be ß character in ASCII, so it was probably some German city name.

Our site’s character type is UTF-8, and Ruby 2.0’s default encoding is UTF-8. I also verified that Encoding.default_internal and Encoding.default_external are both UTF-8. It was our cache provider inserting non-UTF-8 character in request header.

No problem. I will just force UTF-8 encoding on the string.

Then, I was faced with another kind of problems.

ActionView::Template::Error: partial character in source, but hit end

Something is off.

Off to the best debugging method in Ruby – print the string encoding. And it’s ISO-8859-1 (or Latin-1).

So, the final solution was to force ISO-8859-1 encoding and encode it again in UTF-8.

string.to_s.force_encoding("ISO-8859-1").encode("UTF-8")

However, I am not 100% happy with the solution. It just smells. It works for now, but I need to look for better solution when I get a chance.

For bonus, check this out – [The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)][1]

Post to Twitter

MongoDB Query Performance Gotchas

At my current job, we use mongodb as our main database and as you can imagine we query our database a lot. The followings are what I found while investigating some slow performance. Hopefully it will prevent you from making the same mistake or pinpoint the source of problem quickly. We are using Rails 4 with Mongoid.

1. Don’t use regular expression with /i in queries.

One of the offending query looked pretty innocent. Customer is embedded document with email attribute and email field is indexed.

def self.with_email(email)
  self.where("customer.email" => /\Aemail\z/i).count
end

When I ran Benchmark.bmbm where the method was repeated 100 times, it returned the following result.

       user     system      total        real
   0.090000   0.010000   0.100000 ( 27.656723)

Compare that with when you call the same without regexp.

def self.with_email(email)
  self.where("customer.email" => email).count
end

Performance result is day and night.

       user     system      total        real
   0.080000   0.000000   0.080000 (  0.122888)

So, why the difference? I couldn’t quite figure it out myself. I knew that Mongodb uses B-Tree for index and index for email was already created. What about the regular expression was making it slow? I thought perhaps the anchor tags (\A and \z) were causing it, but that wasn’t it. I tried using substring of email and anchoring the beginning of email string (using ^), but that didn’t yield difference either.

I finally turned to Stack Overflow for assistance, and within a few minutes, someone provided exact answer I was looking for. They key to the answer was in output of explain method.

Look at the nscanned and indexBounds in the output of explain method for the first method. It scanned all index because the upper and lower bounds are not defined ("" and {}).

{
                     "cursor" => "BtreeCursor customer.email_1",
                 "isMultiKey" => false,
                          "n" => 781,
            "nscannedObjects" => 781,
                   "nscanned" => 500000,
    "nscannedObjectsAllPlans" => 781,
           "nscannedAllPlans" => 500000,
               "scanAndOrder" => false,
                  "indexOnly" => false,
                    "nYields" => 1397,
                "nChunkSkips" => 0,
                     "millis" => 406,
            "indexBounds" => {
    "customer.email" => [
        [0] [
            [0] "",
            [1] {}
        ],
        [1] [
            [0] /test/i,
            [1] /test/i
        ]
    ]
  }
}

Compare that to the output of explain method for the second method. Exactly the same upper and lower bounds, and it only scanned extremely small number of objects. This explains the big performance difference between the two methods.

{
                     "cursor" => "BtreeCursor customer.email_1",
                 "isMultiKey" => false,
                          "n" => 230,
            "nscannedObjects" => 230,
                   "nscanned" => 230,
    "nscannedObjectsAllPlans" => 230,
           "nscannedAllPlans" => 230,
               "scanAndOrder" => false,
                  "indexOnly" => false,
                    "nYields" => 1,
                "nChunkSkips" => 0,
                     "millis" => 0,
            "indexBounds" => {
    "customer.email" => [
        [0] [
            [0] "test@email.com",
            [1] "test@email.com"
        ]
    ]
  }
}

2. Don’t convert collection to array

Another slow performance was due to the following line of code. ProductA collection had about 20 documents and ProductB collection had about 2 documents. Another seemingly innocent code, but why?

products = ProductA.all + ProductB.all

Back to measuring performance with Benchmark (this time I just did it with Benchmark.bm).

Benchmark.bm do |x|
  x.report {n.times {|n| products = ProductA.all + ProductB.all}}
end
       user     system      total        real
  99.810000   2.630000 102.440000 (114.282440)

Let’s confirm the performance of retrieval.

Benchmark.bm do |x|
  x.report {n.times {|n| ProductA.all.count}}
end
       user     system      total        real
   0.430000   0.000000   0.430000 (  0.437339)

Benchmark.bm do |x|
  x.report {n.times {|n| ProductB.all.count}}
end
       user     system      total        real
   0.440000   0.000000   0.440000 (  0.456449)

That’s pretty reasonable performance. So, it must be something in the addition of two collections. When you add two collections using Mongoid, it returns an array, so it might be something related to converting to an array. Let’s check the performance on that.

Benchmark.bm do |x|
  x.report {n.times {|n| ProductA.all.to_a}}
end
       user     system      total        real
 110.070000   1.640000 111.710000 (117.081572)

Ah-ha! Looks like we found the problem. Converting to an array is quite slow. In order to use single collection, without converting to an array, I created a parent class – ProductParent, and ProductA and ProductB would inherit from that class. In such way, one collection is used and subclasses are distinguished by just type field. Actually, it should have been parent/subclass structure since ProductA and ProductB are kinds of a Product, and both share many of the same attributes.

After the re-arrangement, the following is the performance.

Benchmark.bm do |x|
  x.report {n.times {|n| ProductParent.all.count}}
end
       user     system      total        real
   0.480000   0.010000   0.490000 (  0.490489)

What a difference it made!

Finding these two performance gotchas have been a fun journey, and I hope they are useful to you. Do you have any gotchas you have found? Let me know, and I will post a link here!

Post to Twitter

Practice programming like you practice martial arts

I have been taking a zen meditation class, which consists of one hour of meditation and one hour of buddhist teaching. I haven’t felt all the physiological benefits of meditation yet – I struggle to stay awake during meditation, but the buddhist teaching has been pretty interesting.

In one class, he used a quote from Enter the dragon to explain how you should not take the buddhist teachings literally.

Don’t think. FEEL. It’s like a finger pointing at the moon. Do not
concentrate on the finger, or you will miss all of the heavenly glory.

It made me think of my journey to reach 2nd-degree black belt in TaeKwonDo. It took me about three years in Korea, and as opposed to many TaeKownDo schools in the US, it was pretty intensive. Everyday, we start with practicing the same kicks and punches – white belts to black belts. You can tell the difference between kicks from white belts and black belts, but where the difference is starkly obvious is during sparring. So, how are they different? Higher black belts can do without thinking. It’s almost their 2nd nature or sixth sense. Their response or counter attack is very quick that sometimes their counter kick/punch lands before the opponent. Even as a 2nd-degree black belt, I still had to think about what opponent does and how I would react. I believe it comes from constant practicing.

When I think about good developers I have witnessed/interacted with, they seem to see beyond surface of problems and are capable of coming up with adequate and correct solutions quickly. As I write more and more codes to solve more requirements and bugs, I began to recognize the pattern and past mistakes I have made which in turn has been enabling me to write better codes with less mistakes more quickly. I have been told that the best way to good at coding is by coding a lot and reading good codes. It’s probably not the case for all developers, but I believe the practice indeed make many developers better.

I’ve practiced a lot of coding at Hacker Dojo (Dojo means a training place) and Ruby Koans (paradoxical questions to reach sudden intuitive enlightenment) helped me a lot in learning Ruby. Their similarities with martial art practices are quite keen.

I will leave another quote of Bruce Lee, that’s also very relevant to coding.

Quote-Ten-Thousand-Kicks-Bruce-Lee

Post to Twitter

Importance of owning a market segment – Monopoly, market leader, and innovator’s dilemma

I am having a great time listening to lectures for Stanford CS183B – How to start a startup online. All lectures have been extremely good, and it allowed me to get a sense of how Y Combinator accepted companies into its batches and what made them successful. I am learning so many things, and I see some common underlying themes I want to write about, but two lectures really struck a chord with me.

Before the Startup by Paul Graham and Business Strategy and Monopoly Theory by Peter Thiel, in my opinion, were dead on. Many startups were able to thrive on because many of their ideas seemed bad at the time. If you have an obviously good idea, then many people will go for the same idea. That leads to competitions. For consumers, competition is good, but for business not so. And in a sense, overarching goal of a business is to become a monopoly in its market.

I find Peter and Paul’s main points similar to those of Crossing the Chasm and Innovator’s Dilemma.

In Crossing the Chasm, the author, Geoffrey Moore, argues that in order for disruptive technology company to survive, it needs to reach beyond technology pioneers and early adapters and move to early majority market. The gap between them is so great that many technology companies fail, and he named it “chasm”. What’s the strategy for crossing the chasm successfully? He coined the first market segment in early majority “beach-head market”. This is where company has to put all its resources and try to conquer. Company can get it wrong, of course, and it’s imperative that company finds this sooner than later so that it can correct its course, and hopefully new one is the right one.

One thing he emphasizes in conquering the beach-head market is to be the market leader. Who is market leader? I believe it’s synonymous to monopoly. You need to have at least 60% of the market share in the segment. Market leader has several advantages over #2 and #3 in the market. Because of its reach in the market, there will be auxiliary companies supporting the market leader, thus creating the whole eco-system. Often times, cost of changing product from leader to another is so great that it gives the leader leeway with its customers. After taking the leadership, it can expand to adjacent markets with money and time it earned being the market leader of beach-head market (he compared to going to adjacent markets as using the top pin in bowling to knock down other pins). If I remember correctly, Geoffrey Moore suggested the beach-head market be adequate enough for a startup to tackle.

Similarly, in Innovator’s Dilemma, the author, Clayton Christensen provides examples after examples, time and time again, a startup seems to come out of nowhere and take over the 900-lbs. gorilla of the market. What’s interesting is that companies in Clayton’s examples represent diverse markets – consumer, enterprise, and even to steel mills. They all had a few things in common.

They all started by attacking the market segment with much lower margin so market leader is happy to let them take it. Market leader is usually larger in size, and thus require much higher margin to operate and make profits. While market leader grows nominally by producing products for handful of larger customers, startup becomes leader in its segment and advances its products at faster rate. When the market leader notices startups’ progress, it’s often too late and even its larger customers are ready to become startup’s customers.

Those two books definitely shaped my views of startups, and Paul and Peter’s lectures seem to validate the books’ main points. There are, of course, many other things that contribute to a startup’s success or failure – co-founder dynamics, team, culture, executions, and any external events. However, I believe, one thing is sure to attribute to startup’s success.

It could be that it’s a market segment on one cares or that the idea you are working on seems to be bad to everyone else. Whatever it is, startup needs to become a leader in market segment to survive and succeed.

Become a leader or monopoly in a market segment

Post to Twitter