> Steve says Android is Google’s most important channel. That’s only if you don’t measure by money. From a business point of view, AdWords is five times more important than anything else.
How is AdWords the channel? It seems like the product to me, while Google Search is the vehicle for delivering them.
>My personal opinion is that Android originally existed to prevent Apple getting a monopoly lock on the hand-held market and lock Google entirely out of mobile ads.
Apple's business model doesn't lend itself to getting a monopoly lock on any business they're in. Apple was always destined to having a nice chunk of the premium market, but someone else would have sprung up to serve everyone else. It could have been Symbian, Blackberry, Microsoft, etc.
> Steve says Android is Google’s most important channel. That’s only if you don’t measure by money. From a business point of view, AdWords is five times more important than anything else.
Even that's misquoting Yegge, he in fact said:
>> Android is probably Google’s most important channel — if not today, then certainly over the next ten years.
He's not even saying it's a more important channel than search today but something that has the potential to be in the next decade.
Additionally after rereading Yegge's post, I don't see anywhere he asserted AdWords is a channel either, which it clearly isn't. He states channels are merely a proxy for ads or it's "little sister" paid subscriptions.
And when you're speaking of channels, as something entirely distinct from ads/subscriptions, then it's clear they must be things customers want: positive experiences, good content, social gratification, etc. Aka, good products. Users are not just a faceless question mark before + "impressions for ads money = profit". It takes hard work to keep users happy in order to even have the opportunity to show them ads or sell them subs. So you're entirely correct here.
Google is very much in the business of customer happiness, as much as they are in the business of keeping advertisers happy on the other end. They are not merely middlemen for advertisers... they control plenty of channels.
Which I believe is based in a common myth about businesses in general, popular among anti-capitalist political ideologies: that industry is only about "making money" - as if that is somehow distinct from providing value to customers. Absent a central body ala governments or in some cases monopolies, it's impossible to make money without providing value in return, aka keeping 'end-users' happy.
I think it’s easy to look at it with hindsight and say that Apple’s positioning was inevitable, but I certainly didn’t feel that way ten or even five years ago.
As is, google pays Apple already a lot of money to be the default search engine on their phones. I imagine that number could have been triple that if no credible rival emerged in the medium/high end phone space.
There's about a 0% chance of a company that doesn't license or open up their platform not having a credible rival, because by default, there's a huge open market they're leaving on the table. This is the same with Tesla, and why Tesla cannot be more than a niche member of the EV market in the long run.
If anything, the companies we need to worry about are those who offer extensible "open" platforms that build partnerships with most of the industry, while retaining control and decisionmaking authority over them all.
What’s wrong with a possible universe where the iPhone is the only modern smartphone, ubuntu/sailfish/Firefox rules the low end, and Tizen or something is keeping one manufacturer alive in the medium end? There are very strong network effects to an app ecosystem, and you can imagine a future where all the high end users are on iOS.
If Ubuntu and the like were successful with a strong ecosystem on the low end, why wouldn't they find someone to build a high end device? Companies that just... don't like profit, perhaps?
Android won it's success in the budget market, and that gave it the ecosystem it needed to survive in the high end market.
The network effect is a chicken and egg problem that can’t be solved with just finding a partner. A large part of why android succeeded because it solved the chicken and egg developer - user problem by being early enough, and by having a company like google put their full support behind it. Other platforms were late to the table incompeting with iOS (windows), or didn’t have the clout of a large competent software company backing it, or both.
Apple's business model doesn't lend itself to getting a monopoly lock on any business they're in.
Their primary products are application platforms. How on earth do you reason that their business models don't lend themselves to lockin, when it's the exact same business model that created Microsoft?
By definition, if you achieve monopoly lockin you can charge whatever price you like. There are people who can't afford / would rather not pay for Windows but find they have to anyway, due to some business critical app they need. They're locked in. That's the point.
premium is kinda debatable when we are talking about phones.
They are heavily subsidized by the phone operators in most markets (sure you end up paying at least as much to the operator, but most people only see the upfront cost).
There are always multiple generations on sale at the same time, and lower cost iterations of the current gen as well.
Not to mention refurbished phones.
In the USA, iOS is roughly half of the smartphone landscape. Yeah, the less costly iPhone is more costly than the cheapest Android phone, but I don't think it can be said that it is premium hardware.
“thought-leader-ish” people --- the author doesn't really respect those people, and thinks JS is not a great language to build anything game changing.
Where Yegge is wrong is that he thinks somehow Grab has moral authority or high ground over Uber. Once he finds out all the scummy things they and everyone else has done in South East Asia, he might have second thoughts about his holier-than-thou attitude.
> Steve correctly notes that front-end programming is hard, but leaves out maybe the single most important reason why: It’s super-hard to unit-test properly.
- UI code spends most of its time interacting with a UI API (Android view framework, whatever iOS uses, DOM/CSS in web). These APIs are enormous and are rarely designed with testing in mind. Mocking or faking the pieces of API that you need to interact with is frequently a daunting or impossible task.
- Followup to the above: because so much of the "work" involved with UI code involves interacting with another API, usage of that API tends to spread itself through the entire codebase like cancer. You can create a careful separation of concerns, but it takes a lot of upfront work, verbose boilerplate code, and constant vigilance -- if you're just handed an existing UI codebase you won't have that luxury.
- UI code is highly stateful and highly mutable. A core skill in UI programming is managing your app's enormous state profile. Single-path, whole-world rendering techniques like React/other shadow DOM techniques really help here.
- UI is highly temporal. It needs to change over time. Testing anything to do with time is an enormous headache. Animations can force you to temporarily separate your underlying state from its representation, which is a testing nightmare. But just in general, writing unit tests that involve time passing is infuriating and fragile (even if you can control time passing via a mocked clock object).
- A lot of core functionality in UI involves different pieces handing off to each other -- one window transitions to another window, etc. To test that properly you need integration tests, but now your integration tests also need to interact with the underlying OS/browser (because you can't separate any of that stuff out). So your integration tests are in general way flakier than you can get on UI-less systems that really only need to worry about faking out a DB of some kind.
Not to mention that UIs are visual, i.e. defining what is “correct” in terms a computer can understand is very hard. There are dozens of criterias (colors, spacing, borders, shadows, fonts, behavior, etc.), and often what is accetable is fuzzy and sometimes even subjective.
Take spacing: if something moves 200px it's probably broken. But a couple pixels off are usually fine. Unless those 2px are the vertical position of an icon inside a button or two things that need to align. Where do you draw the line? Humans are pretty good at spotting when things look off just by looking at a screen. Computers, not so much (yet).
This comment is probably missing the biggest part of the problem: The vast number of end devices that will need to present the UI. Even if you're building for iOS, there's several different devices that you need to account for, each with their own quirks, shapes (notches?). But once you go talking Android or web, you're talking about hundreds of potential niche cases, and all of these can change on a yearly basis.
Unit testing frontends is hard because to create a test case, you must simulate a human user's behavior (clicks/taps on a UI) which is inherently complex, and has a lot of possible variations, and then test the correctness of the response the system displays as a human would perceive it. Just because the system sent back the correct data doesn't mean it was rendered in a way that the user can see/understand.
With non-user-facing systems, you can just send the input, and test computationally that the output fits the expected value or range of correct responses.
Of course, one could create a vision system that tested the response of a UI for correctness, but that would be ... super-hard.
It's wrong. UI code isn't hard to unit test. It's borderline-impossible to integration test the state of the art in "controlling a browser to poke at your UI" is woefully inadequate, as are the debugging mechanisms available when anything unexpected happens. And I'm talking about a single-browser suite of tests, not even trying to assess cross-browser testing, testing on the nigh-infinite number of (device-spec * OS version * "value added" OEM android garbage libraries * custom build of chrome) matrix that is mobile devices.
It's wrong anyway, if you're someone who doesn't bother with unit tests writing front-end code is still a nightmare compared to back-end programming. So it can't be the unit tests that are the problem.
It's more a problem that iterating/debugging/testing is generally so much harder for front-end, however you do it and regardless of whether you're dogmatic about unit testing or not.
Focusing on the difficulty of unit testing is simply focusing on one of the symptoms rather than the root cause.
Like in backend code, I can back out of a method, rollback to the start of a call and re-run it all again when debugging. In front-end code, that's simply not possible because there were a bunch of user interactions and you can't re-run them, you have to restart and click, click, click.
It got a lot better unit testing UI recently especially being able to snapshot test different scenarios. In the end if you have stateless React components testing with jest and enzyme is easy. Again supplying state hooks for the various different interactions a more complex component might have is perfectly possible.
Additionally separate your components logic from rendering and test that; e.g. a calendar widget I just created has a load of tested functionality for creating lists of dates with various attributes (isCurrentMonth, isToday, isSelectable, isSelected, etc). This can be unit tested just fine.
Finally I’d strongly recommend cypress for doing e2e testing.
AFIK, thats not unit testing. When you can write unit tests, they are usually lighter, faster to run and easier to maintain. You would use Selenium for integration testing.
This is a great question. The answer is that it depends on what you mean by "unit test". I will actually state that it is not hard to unit test front-end (or more generally UI) code, but I think that the reason for my differing answer is far more interesting than the answer itself.
First, why do many people think that unit testing UI is difficult? How do you unit test UI? There are a couple of schools of thought about "unit tests". A very prevalent one is that you write a "unit" (usually a class) and then you stress test the interface. Often this is coupled with faking/mocking collaborators because we are only interested in testing the interface.
This is kind of problematic with UI code because imagine that I have a class that is derived from a dialog box. How do I test (for example) that the desired functionality is run when I hit the "OK" button? The problem is that the "OK" button is often not a programmable interface on my dialog box. Someone clicks on the button, whatever UI framework I'm using takes over and then magically some callback (hopefully) get's called. I can (sometimes) hack into the depths of my framework and maybe mock the callback to make sure it gets called when a button is pressed, but usually frameworks are not built to accommodate this kind of work. I can also use some kind of UI simulator to press buttons and that would work OK. But I'm going to back up here and suggest that this is not a unit test. It's an automated regression test.
Part of the problem is the framework is "hiding" the internal functioning of the UI. I can't test the OK button, because I just can't get access to it. For me this is a big hint that "I'm doing it wrong". In fact, I don't subscribe to the common view that "unit testing" is about testing the interfaces on a class -- in other words, black box testing. Unit tests are specifically different than other kinds of test: they are white box tests.
I've described this a few times and have yet to find a way that works particularly well, so forgive me if I fail yet again (you can happily walk away with only the first half of this message :-) ). Imagine that instead of "testing", we simply want to insert "probes" into our code. The probes will measure the operation of the code in a specific place and warn us if something is outside of our expectations.
For example, imagine cooking a roast beef (sorry if you are vegetarian -- you can imagine some other kind of roast). We want to cook the roast to a certain internal temperature. There are many ways to do it. A "black box" approach would be to weigh the roast, measure the temperature in the oven and then time how long we are cooking. We can then derive the probable internal temperature from these external parameters.
The "white box" approach would be to stick a thermal probe (thermometer) into the roast and measure the temperature directly. This allows us to see exactly what's happening on the inside, but at the cost of violating the roast's encapsulation.
My opinion is that "unit testing" is this latter kind of testing. We want to expose the internal state of things and to measure it directly -- rather than deriving what we assume the state to be from some defined interface. I furthermore believe that "TDD" refers to the systematic act of finding appropriate internal state and exposing it. Test first is a good way to do that because you end up probing the state before you have written any interfaces -- it forces you to open up that internal state. There are other ways to do it, though.
All of that to say that UI code is not actually any different than any other code. Our difficulty is not that the events driving the system are generated by a user. Our difficulty is that the frameworks hide the internals and stop you from writing unit tests (by my definition). This happens frequently when you are trying to TDD legacy code. The legacy code was not written in a way that allows you to write unit test -- you are forced to write integration tests because you don't have access to the internals. This is exactly the same with most UI frameworks -- they were not written to allow unit testing. And since you can't (or really don't want to) start refactoring the framework, you are stuck.
Having said that, I have found some frameworks to be amenable to unit testing. For me, the best I've found in the web world is React. Interestingly, though, I do not use the React testing framework because it is not amenable to unit testing (by my definition). I build my own.
You successfully described why I think unit testing can be harmful to good code - forcing exposure of too many internal details.
This has further implications, like over-abstraction (all those dependencies need to be parameterized, all those classes need to be interfaces, everything must be indirected so it can be probed), namespace pollution (instead of a cohesive external API, you get a big bag of Lego pieces and have to pick and choose the right combination), brittle design (every unit boundary gets tested on both sides, tripling the cost of modification), etc.
I think you are imagining something very different than what I am describing. Exposure of state simply allows you to decompose your structures -- which allows you to compose them again. This is exactly what you do in FP. Testing at branch points means that you write 2 tests. If you have n branch points it means 2n tests. If you test n branch points down, you need n^2 tests. You don't test functionality at every level -- because these are probes not tests. Your external API is irrelevant to its construction, which is the point of encapsulation. I can write internals that can be probed, or I can decide not to. But how you use it from the outside is not related. You can build as many layers of this as you want -- in the normal way.
I'm trying to imagine what you are thinking of, but I'm having trouble so it's hard to rebut your points.
I'm thinking of the dominant paradigm in Java OO from about 2005 to 2015 or so.
Choose almost any moderately popular jar you like from Maven and I could point out the pathologies. Strong smells when you have lots of interfaces with a single implementation, lots of construction indirected through factories (or factory factories), etc.
So it looks like Tim Bray is not refuting Yegge's central point: that Android is vulnerable to "stealing" due to someone else (the RN community, which i have to point out is much bigger than Facebook at this point) developing a true xplatform alternative. Thats a very non obvious conclusion and I went from total ignorance to completely agreeing with it in the span of one post. Do people actually agree that Android is that vulnerable?
and what -is- the deal with Flutter? Is it Dart 2.0?
FWWIW, the article was discussed a bit in the Android slack I hang around, and quickly dismissed.
The consensus is that there are always big downsides to cross platform solutions and that it is not going to change anytime soon. They have their niche, but currently have zero chances to replace native.
Flutter is a runtime for Android and iOS powering apps written in Dart.
Flutter itself is written in c++ and Dart.
The main originality is that it uses it's own runtime instead of using the platform widgets. It is not as original as its creators would like you to believe though since that's basically what all the cross platform toolkit running in a webview has been doing. The difference is that performances are not atrocious with flutter but they still fall short of being any better than native apps.
Flutter could be a big deal if/when Fuchsia becomes a thing it is adopted as its main app runtime. And by 'become a thing' I mean that it completely replaces Android.
You would get native dev on 'android z+' and high quality iOS ports very easily.
>Steve correctly notes that front-end programming is hard, but leaves out maybe the single most important reason why: It’s super-hard to unit-test properly
Yeah, no, that's hardly the reason.
Besides, it's wrong. It might be harder to functional or integration test properly, but unit-testing front-end code properly is not an issue.
100% agree on functional/integ/end to end testing being harder for fronentd. On the other hand, nobody seems to unit-test Javascript where I am. Maybe they're just silly, or maybe it's harder, maybe it's just a lack of tooling.
As an aside, it is actually more important to unit test lest "safe" languages. E.g. Java ensures you're passing correct types around at compile time. But with JS/Python et al. you need to unit test to check that you're passing, say a String rather than a tomato.
That is an engineering culture thing. I work on a small JS project (node.js server + React FE) that has >95% unit test code coverage. It isn't even difficult to do - it is just not a major part of a lot of front-end teams culture.
There are a lot of good unit testing frameworks for javascript. I've worked on teams using them for significant codebases with high unit test coverage for more than 15 years.
It's not like I disagree, but the first point is the same god damn pedantic point that gets hit over and over again, that Google's customers are advertisers rather than users. We get it already, and it ignores Yegge's actual point to say the same thing we've heard a million times before.
If I never have to read "Unless you're paying, you're not the customer you're the product" again, that shit will be too soon. If they don't make something that people actually want to use, there will be no audience for advertisers. Come on.
Lastly, I thought it was funny that both Yegge and Bray can agree to take shots at JavaScript. There's another thing you'd think nerds would get tired of already.
> If I never have to read "Unless you're paying, you're not the customer you're the product" again, that shit will be too soon. If they don't make something that people actually want to use, there will be no audience for advertisers. Come on.
Your point is great, and important. The situation is more nuanced than customers vs users. Google has multiple types of customers, and both are important. Free customers using search still have to be appeased by search features, and not too irritated by ads, otherwise ad revenue goes away. Ads customers have to reach a large audience, otherwise they go away. Like many companies, internally Google has departments that are in a sort of competition with each other, and the tension has to maintain an important balance. Ads can't be the only customer, and it can't be the only thing Google cares about.
While I'd agree it's getting a bit tired, the context where this aged phrase makes more sense is when discussing privacy. I've seen it most often used to try to get the point across that privacy will never be a goal of free ad-supported internet services. Tired as it is, that point might be worth repeating until the general population and the government actually take it seriously.
BTW, I didn't see any shots at JavaScript here, my take was he was defending it.
I don’t think it’s a pedantic point here; it’s one of the only times this statement is truly relevant to the conclusion you’ll draw from the data.
To rephrase Yegge’s original question with this lens: is Google focused more on generating revenue from its customers (advertisers) by hooking users into their service ecosystem? Or are they being unwarrantedly distracted by “competitors” of their offerings, when users’ interest in those competitive offerings isn’t actually decreasing their attachment to the Google services ecosystem at all?
You may be familiar with it, but reading Yegge's post, I'm still not confident he understands the difference. At least in that section, he seems to treat "customers" and "users" as equivalent groups. For some businesses that's fine, but it's definitely not so for Google.
It seems like his real point is that Google is not being innovative on the grand scale. Which is fine, but that's distinct from not being user-focused, and distinct again from not being customer-focused. Those are three different problems, and they get solved three different ways.
> Lastly, I thought it was funny that both Yegge and Bray can agree to take shots at JavaScript. There's another thing you'd think nerds would get tired of already.
Why? JavaScript is really, truly, awfully horrible. It's a local maximum which could easily be escaped with just a very little bit of effort, and the fact that no-one has done so is one of the strongest-possible condemnations of our industry. JavaScript is a shame, an embarrassment and a squandered opportunity. When one thinks that we could have had Scheme, and instead thanks to a benighted Netscape executive we're stuck with JavaScript forever — it is to weep.
I disagree, I enjoy programming in JavaScript, and I've been around the block. Language and ecosystem improvements have made it a productive (if somewhat quirky) language. We use NodeJS as our backend language at our (serious) software company and it's well tested, clean, and maintainable.
Eventually WebAssembly will allow you to use whatever language you want.
> When one thinks that we could have had Scheme
This may have been true 5 years ago. I'm probably the biggest Scheme fan there is. I've created assemblers, compilers, and even started an OS in Scheme. I've been using Scheme since the late '90s.
Modern ES6 and beyond JavaScript is quite nice. I really don't miss Scheme at all. Scheme, mind you, was incredibly limited in R4RS and R5RS, around the time Netscape would have adopted it anyway. It didn't even have a module system, much like old JavaScript. We would be stuck with the largest problem still facing JS: multiple sucky module systems requiring a webpack-like monstrosity.
Single-threaded in a multicore world is nice? Implicit type coercion on par with PHP is nice? Implicit var args are nice??? (That's the worst part by far). I would choose pretty much any non-shell mainstream programming language over JavaScript for a program with results I care about (that is, a useful program). Throwing a bag of syntactic sugar (ES6) on a rotten language is meaningless.
Javascripts approach to threading - default single threaded event loop, but with message passing to communicate with other threads is actually a pretty good model for people who want to write multi-threaded code that doesn't break. This is important when coding for a very open platform like the web. Confusion about what is running on the UI thread and what isn't and how to communicate between them is the kind of error that pops up in java ui code. I wouldn't want that for the web.
Besides, the threading approach is more about the runtime rather than the language. There are lots of clustering and threading libraries on npm if you want them for your server-side code, and you have WebWorkers in the browser.
Sure, the implicit type coercion (pretty much everyone hates this) and var args (hasnt bothered me as much as it seems to have bothered you) were not good choices, although compare it to other languages of the time - first class functions were by no means universally available and now almost every modern language has them. A literal notation for maps in the language was a great decision too. Prototype inheritance may be a little weird but it is elegant, more general and radically simpler than class based inheritance.
Javascript certainly has its warts but I find it fairly productive to code in. Plus it's paired with a runtime that has seen a shocking level of genius engineering over the last 10 years. The speed of iteration is unparalleled. The reach of a deployed piece of code is unique and likely to remain so for the foreseeable future. There aren't many other platforms that have developer tools for inspecting a running system, visualizing ui, network and detailed render performance that are as good.
> Javascripts approach to threading - default single threaded event loop, but with message passing to communicate with other threads is actually a pretty good model for people who want to write multi-threaded code that doesn't break.
This is simply wrong. The "approach" to threading is that there is none. It's single-threaded. You cannot write multi-threaded code directly in JS. On the server side, this can lead to things like a naive fetch after cache miss denying service to your web application. Nothing on the queue can run until the current function call finishes. Even lovely Python doesn't have this issue because, while the GIL is a PITA, Python has real threads, and can switch during a function call.
To be clear, I'm not talking about web browser programming, where JS for some time has been the only option. I'm talking about the ridiculousness of server-side JS when we know clock speeds are hitting a wall and that parallelism is the only way to squeeze out more performance. Steele, Armstrong et. al. have lectured at length on this topic.
> There are lots of clustering and threading libraries on npm
No, there aren't. Running several node processes via PM2 is not threading. You cannot use multiple cores directly from the same Node program unless you drop down to C++.
You can vaguely do it in the browser, but the limitations on communications between the main thread and web workers, especially with SharedArrayBuffer being off-limits post-Spectre, are pretty much non-starters. It's a nice option to have for specific cases (games programmers take advantage of web workers to read models without blocking the main thread, for instance), but it's only bolted onto web browsers.
> You cannot use multiple cores directly from the same Node program unless you drop down to C++.
Well, someone has to drop down to C++, but it doesn't have to be me (node webworker-threads). This is the same as in most languages.
> you cannot use multiple cores directly from the same Node program unless you drop down to C++.
As I said in my comment, threading is primarily a runtime thing, not a language thing. There are javascript runtimes (napa.js, node webworker-threads, nexusjs, browsers) that have threading (even by your restrictive definition that doesn't include threads layered onto child processes like the npm package 'threads' does), just as there are runtimes for e.g. java that do not (and the bulk of the threading support in most other language runtimes is also written in C++ so it seems churlish of you to complain about that in javascript runtimes). Most languages do not need significant changes to their syntax or keywords to support multithreading.
Maybe you're comparing node.js specifically (where I think that for a long time there was a belief among the leads that letting the OS manage processes was a better approach - it's been interesting to watch this same argument play out in the rust community) with something like Go which has pleasant primitives for concurrency built in as part of the language. If you are, then to some extent I agree with you - something like goroutines might be really nice in javascript and is arguably better than what the js community has, but I also stand by my runtime/language distinction. Goroutines are not OS threads. You can run go programs with GOMAXPROCS set to 1 without changing the language at all.
HN is not allowing me to edit my adjacent comment (11 minutes ago...), but I meant to add:
I'm sort of amazed that the implicit var args don't bother you... with var args promoted to first class syntax in ES6, the only reason they're still there is for backwards compatibility. Passing an unhandled arg to a function should at least be a runtime error, and likewise omitting a positional arg that lacks a default. I've seen countless bugs caused by this "feature" alone. When I think of JS programming in the large, I think of "undefined is not a function" and "cannot read property 'foo' of undefined." It's quite hellish.
My understanding is that we do (or did) mostly have Scheme with the first release of JavaScript, just with different syntax. What about Scheme, what features or syntax, would be so much better than JS that we should switch?
Would you elaborate on what makes JavaScript so bad? How much have you used it yourself? Having done lots of C++ in my life, I find writing JavaScript quite a bit more enjoyable. Especially recently now that the dev tools in all the major browsers have gotten so good.
> It's a local maximum which could easily be escaped with just a very little bit of effort, and the fact that no-one has done so is one of the strongest-possible condemnations of our industry.
I figure, there are 3 possibilities:
(1) you're right, and that Javascript is horrible, and the entire software development industry is lazy in not replacing it.
(2) it's actually very difficult to replace
(3) it's not as bad as you think it is.
I'm not sure which is correct, but I wouldn't expect it to be the one that requires malice or incompetence on the part of an entire industry of people who love replacing thing.
Feel free to exert that 'just a very little bit of effort', for all our sakes. If it's that easy it shouldn't take more than a couple of days, right? :)
I jest. ECMAScript is the most widely installed programming platform on the planet. Ever. How do you even begin to shift that?
I'm not sure what JavaScript being the most widely installed platform on the planet has to do with it being a good programming experience. You want to program for the web? You must use Javascript (or something that compiles to Javascript), I don't think many choose Javascript because it is a great programming experience.
You comment seems to miss the point of the parent. Regardless of the programming experience, lots and lots of people and platforms use it. Due to network effects, it would be very difficult to shift all of those to a different language.
How is AdWords the channel? It seems like the product to me, while Google Search is the vehicle for delivering them.
>My personal opinion is that Android originally existed to prevent Apple getting a monopoly lock on the hand-held market and lock Google entirely out of mobile ads.
Apple's business model doesn't lend itself to getting a monopoly lock on any business they're in. Apple was always destined to having a nice chunk of the premium market, but someone else would have sprung up to serve everyone else. It could have been Symbian, Blackberry, Microsoft, etc.