Mobile development blogs, tutorials and resources inside!Latest Mobile Dev Insights: iOS, Android, Cross-PlatformAdvertise with Us|Sign Up to the NewsletterMobilePro #224: Putting Companion Objects in Their PlaceHi ,As AI gets better at writing code, the question shifts from "Can it build this?" to "Should it be built this way?"That's where software design still matters. This week's article looks at one of Kotlin's smallest language features, the companion object, and why it has an outsized impact on code organization. Used thoughtfully, it keeps a class cohesive and expressive. Used carelessly, it becomes another place where complexity quietly accumulates.That feels particularly relevant this week. Swift continues evolving alongside Apple's AI ecosystem, Android Bench is improving how AI coding models are evaluated, and GPT-5.6 pushes agentic development even further. The tools are getting remarkably good at generating code, but they're still relying on developers to make sound architectural decisions. Companion objects are a reminder that clean software isn't just about syntax—it's about knowing where responsibility belongs.TL;DRCompanion objects are Kotlin's idiomatic way to define class-level members without using static.They work best for constants, factory methods, and small helpers that conceptually belong to the class.Because companion objects are real objects, they can hold state and implement interfaces, making them more flexible than Java's static members.Avoid using companion objects as containers for global mutable state or unrelated utility functions.If a companion object keeps growing, it's often a sign the class should be split into smaller, more focused components.As AI generates more boilerplate code, good architectural decisions like these become even more valuable than the code itself.This week’s news cornerApple Seeds Fifth iOS 26.6 and iPadOS 26.6 Betas to Developers: Apple has released the fifth iOS 26.6/iPadOS 26.6 developer beta, a week after the fourth, as it winds down iOS 26 ahead of September's iOS 27 launch. The update is mostly bug fixes and performance work, with a blocked-contacts limit notice and a possible anti-snatching lock feature.What's new in Swift: Apple's June 2026 Swift roundup covers major WWDC26 announcements—including Swift-written OS kernel components, a faster Swift 6.4 preview, an open-sourced QUIC networking layer, and new Foundation Models framework tooling—alongside community highlights like Swift Package Index joining Apple and CommunityKit's in-person gathering. It also tracks active Swift Evolution proposals, including withDeadline, yielding accessors, and new noncopyable array types.Evolving how LLMs are measured for Android: Google's July update to Android Bench adopts the Harbor benchmarking framework and adds 8 new models—including Claude Fable 5, which tops the leaderboard at 84.5—while opening the benchmark to community-submitted tasks and evaluations. The methodology change resets scoring baselines, though historical scores remain archived.GPT 5.6 is out: OpenAI has launched the GPT‑5.6 family (Sol, Terra, Luna) for general availability, claiming state-of-the-art results in coding, agentic, and reasoning benchmarks—often beating Claude and Gemini models at a fraction of the cost—plus a new "ultra" mode that coordinates multiple agents in parallel for demanding tasks. The release also introduces Programmatic Tool Calling in the Responses API and emphasizes strengthened safety evaluations ahead of launch.A glimpse of BuildWithAI newsletterBuilding with AI is quickly becoming part of every developer's workflow. Each week, Build with AI explores practical AI engineering, agentic development, LLMs, MCP, coding tools, and the techniques shaping modern software development. Here's a glimpse into a recent featured article:Vibe coding versus agentic engineering – Why the distinction mattersTo proceed, we need to draw a sharp line between what has become known as vibe coding and the professional discipline of agentic engineering.The term vibe coding captures a very real, very widespread phenomenon. Developers sit down with an advanced tool like Claude Code or GitHub Copilot, open a chat window, and begin throwing natural language instructions at the model: Build me a React dashboard with a dark mode toggle that pulls data from this endpoint. The model churns out a massive block of boilerplate. The developer pastes it into their IDE, runs it, and hits an error. They copy the stack trace, paste it back into the chat window, and say, Fix this.In this workflow, the developer is coding entirely by vibe.They are relying on the LLM’s probabilistic predictionsto stumble towards a working solution. They are not defining strict architectures or writing tests. They are merely providing a directional push and letting the model hallucinate the details.For the first forty-eight hours of a greenfield project (a prototype, a hackathon, a disposable script), vibe coding is arguably the most efficient way to build. The lack of constraints allows the model to draw on its training data freely, rapidly bridging the blank-page problem.The trap, however, is that vibe coding doesn’t scale. It fails structurally and spectacularly when applied to enterprise systems.Let’s examine why vibe coding fails in production.Three failures sit at the same structural level, and each one affects a different part of the workflow: output variance, context collapse, and the absence of a verification gate before deployment:Output variance: Ask for the same feature on Tuesday and Thursday and the model can hand you two different architectures, because it samples each next token with randomness baked in. One run gives you a clean repository pattern, the next inlines the same queries across three controllers. Neither is wrong on its own, but the work no longer converges on a stable shape you can build on.Context collapse: As the codebase grows, the developer using the vibe approach has to paste more and more context into the chat window. Eventually, the signal-to-noise ratio degrades. The AI becomes confused, overwriting unrelated components or losing track of the initial objective. The developer makes this worse without noticing, because LLMs are sycophantic by design and exist to satisfy the prompt. Suggest a flawed approach and a vibe-coding agent will happily generate thousands of lines executing it, never pushing back.No verification gate: Vibe coding runs no automated check between generation and acceptance. The developer eyeballs the output, runs it once, and moves on. Nothing catches the variance or the drift before the code reaches production, so the first two failures compound silently.Read more...Book now...Companion Objects in Kotlin:When (and When Not) to Use ThemIf you've spent any time in a Kotlin codebase, you've almost certainly bumped into a companion object. They look small — a keyword and a pair of braces tucked inside a class — but they carry a surprising amount of design weight. Used well, a companion object keeps a class self-contained and easy to reason about. Used carelessly, it becomes a dumping ground that quietly reintroduces the very problems Kotlin's object-oriented tools were meant to solve.This article walks through what companion objects actually are, the situations where they genuinely earn their place, and the situations where you're better off reaching for something else.What a companion object actually isEvery member you put inside a normal Kotlin class — a property, a function — belongs to an instance of that class. You need an object before you can touch it. A companion object flips that rule for a specific, named block inside the class: anything declared there belongs to the class itself, and can be reached through the class name with no instance required.class User { companion object { const val MAX_USERS = 100 }}// Accessed via the class name, no instance needed:Log.d("User", "Limit: ${User.MAX_USERS}")If you've written Java, C#, or a similar language, this will feel familiar: a companion object is Kotlin's answer to static members. Kotlin doesn't have a static keyword, so this is the idiomatic replacement — with one important difference worth remembering. A companion object is a real object under the hood, which means it can implement interfaces and hold its own state, something a plain static block cannot do.When companion objects earn their placeFactory functions and controlled constructionThe most common legitimate use is guarding how an object gets created. A Room database, for example, should only ever exist once per app process. Wrapping the creation logic in a companion object's function keeps that rule enforced in one place rather than trusted to every caller.companion object { @Volatile private var INSTANCE: CelebBookDatabase? = null fun getDatabase(context: Context): CelebBookDatabase { return INSTANCE ?: synchronized(this) { Room.databaseBuilder( context.applicationContext, CelebBookDatabase::class.java, "celeb_book_database" ).build().also { INSTANCE = it } } }}Constants that belong conceptually to the classA value like MAX_USERS isn't data about one particular user — it's a fact about the User type as a whole. Storing it in a companion object keeps the constant next to the class it describes, instead of floating in an unrelated top-level file that future readers have to go hunting for.Small, stateless helpers tied to the classUtility logic that operates purely on inputs — validating a phone number format before a Contact is built, say — often reads more clearly as a class-level function than as a free-floating top-level one, especially when several such helpers cluster around a single type.When to reach for something elseIf the logic doesn't need the class at allA genuinely standalone helper — one that doesn't reference the class's types or concepts — usually belongs as a plain top-level function. Wrapping it in a companion object just to give it a home adds a layer of indirection with no real benefit.If you're using it to fake global mutable stateIt's tempting to stash a mutable list or a shared counter in a companion object so any part of the app can reach it. This works, but it reintroduces the same problems as global variables in any language: hidden dependencies, harder testing, and state that can change from anywhere without warning. If several classes genuinely need shared access to the same data, that's usually a sign the data deserves its own class — often a repository or a singleton passed in explicitly — rather than being smuggled in through a companion object.If it's growing into a second, badly-organized classA companion object that accumulates dozens of unrelated functions is a sign the class is doing too much. At that point, splitting the logic into a proper separate class (or several) will usually be easier to test and easier for the next reader to follow.The MVVM connectionCompanion objects show up constantly in MVVM-style Android code because they map neatly onto the pattern's separation of concerns. A ViewModel's companion object can hold default configuration; a database class's companion object can guarantee a single shared instance; a Model class's companion object can hold constants the rest of the app needs to reference. In each case, the shared, class-level piece is deliberately kept small and separate from the instance-level logic that does the actual work — which is exactly the discipline that makes companion objects worth using in the first place.The short versionReach for a companion object when something genuinely belongs to the class rather than to any one instance of it — constants, factory functions, and small class-level helpers. Avoid it when you're really just looking for a convenient place to stash mutable state or unrelated utility code; in those cases, a dedicated class or a top-level function will usually keep your codebase easier to test, read, and change.This article is based on Chapter 22 of Android Programming for Beginners, Fourth Edition, published by Packt. The book covers Android, Kotlin, and Jetpack from scratch and Turbo charge progress with AI.📚 Go DeeperIf you’re looking to build Android apps with Kotlin, Jetpack Compose, Android Studio, and Agentic Programming, Android Programming for Beginners, Fourth Edition by John Horton offers a practical guide to mastering modern Android development workflows and Kotlin fundamentals.🧑💻 Create hands-on projects including, UI, sound, graphics, databases and game🛠️ Explore Android development techniques such as state management, Material Design, Room databases, Canvas drawing, and responsive layouts📱Learn how to (optionally) use AI to speed up learning and developmentAndroid Programming for BeginnersPre-order now at $44.99📢 Important: MobilePro is Moving to SubstackWe’ll be moving MobilePro to Substack soon. From that point forward, all issues will come frompacktmobilepro@substack.com.To ensure uninterrupted delivery, please whitelist this address in your mail client. No other action is required.You’ll continue receiving the newsletter on the same weekly cadence, and on Substack you’ll also gain more granular control over your preferences if you wish to adjust them later.💭 Let’s TalkHave companion objects ever simplified your code or quietly made it harder to maintain?Reply and let me know.Advertise with usInterested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email and our team will get in touch with next steps.Cheers,Nithya Sadanandan and Runcil Rebello,Editors-in-Chief, MobilePro*{box-sizing:border-box}body{margin:0;padding:0}a[x-apple-data-detectors]{color:inherit!important;text-decoration:inherit!important}#MessageViewBody a{color:inherit;text-decoration:none}p{line-height:inherit}.desktop_hide,.desktop_hide table{mso-hide:all;display:none;max-height:0;overflow:hidden}.image_block img+div{display:none}sub,sup{font-size:75%;line-height:0}#converted-body .list_block ol,#converted-body .list_block ul,.body [class~=x_list_block] ol,.body [class~=x_list_block] ul,u+.body .list_block ol,u+.body .list_block ul{padding-left:20px} @media (max-width: 100%;display:block}.mobile_hide{min-height:0;max-height:0;max-width: 100%;display:none;overflow:hidden;font-size:0}.desktop_hide,.desktop_hide table{display:table!important;max-height:none!important}.social_block .social-table{display:inline-block!important}}
Read more