Context: Searching for a new senior level software development job over a 9 week period in summer 2025.

  • Focused mostly on data engineering and backend roles that are in-person or hybrid in the SF Bay Area.
  • Leads from recruiters on LinkedIn were much more likely to lead to interviews+offers.
  • The winning offer came through my personal network.
  • I mostly used Hiring.cafe for prospecting. They’re a scraper with an interface I didn’t hate.
    • squaresinger@lemmy.world
      link
      fedilink
      arrow-up
      1
      ·
      12 hours ago

      Don’t know if there’s a ready-made site for stuff like that, but it’s not hard to do.

      Here’s a quick and dirty AI generated piece of trash code as a proof of concept:

      # sankey_hiring_funnel_direct.py
      # Requires: plotly
      # Install: pip install plotly
      
      import plotly.graph_objects as go
      
      # Node labels (unique)
      labels = [
          "Network",            # 0
          "Hiring.cafe",        # 1
          "Abandoned Lead",     # 2
          "Applied",            # 3
          "Rejected",           # 4
          "No Response",        # 5
          "Screener",           # 6
          "Rejected by Screen", # 7
          "Full Round",         # 8
          "Rejected by Panel",  # 9
          "Offer",              #10
          "Accepted",           #11
          "Declined"            #12
      ]
      
      # Colors for the two source groups (consistent)
      network_color = "rgba(31,119,180,0.8)"      # blue-ish
      hiring_color  = "rgba(255,127,14,0.8)"      # orange-ish
      
      sources = []
      targets = []
      values  = []
      link_colors = []
      
      def add_link(src_idx, tgt_idx, val, color):
          sources.append(src_idx)
          targets.append(tgt_idx)
          values.append(val)
          link_colors.append(color)
      
      # Direct flows from Network and Hiring.cafe into Abandoned Lead and Applied
      add_link(0, 2, 1, network_color)    # Network -> Abandoned Lead (1)
      add_link(1, 2, 58, hiring_color)    # Hiring.cafe -> Abandoned Lead (58)
      add_link(0, 3, 11, network_color)   # Network -> Applied (11)
      add_link(1, 3, 70, hiring_color)    # Hiring.cafe -> Applied (70)
      
      # Applied -> Rejected, No Response, Screener (split by original group)
      add_link(3, 4, 5, network_color)    # Applied -> Rejected (network 5)
      add_link(3, 4, 40, hiring_color)    # Applied -> Rejected (hiring 40)
      add_link(3, 5, 3, network_color)    # Applied -> No Response (network 3)
      add_link(3, 5, 15, hiring_color)    # Applied -> No Response (hiring 15)
      add_link(3, 6, 4, network_color)    # Applied -> Screener (network 4)
      add_link(3, 6, 15, hiring_color)    # Applied -> Screener (hiring 15)
      
      # Screener -> Rejected by Screen, Full Round
      add_link(6, 7, 1, network_color)    # Screener -> Rejected by Screen (network 1)
      add_link(6, 7, 5, hiring_color)     # Screener -> Rejected by Screen (hiring 5)
      add_link(6, 8, 3, network_color)    # Screener -> Full Round (network 3)
      add_link(6, 8, 10, hiring_color)    # Screener -> Full Round (hiring 10)
      
      # Full Round -> Rejected by Panel, Offer
      add_link(8, 9, 1, network_color)    # Full Round -> Rejected by Panel (network 1)
      add_link(8, 9, 7, hiring_color)     # Full Round -> Rejected by Panel (hiring 7)
      add_link(8, 10, 2, network_color)   # Full Round -> Offer (network 2)
      add_link(8, 10, 3, hiring_color)    # Full Round -> Offer (hiring 3)
      
      # Offer -> Accepted, Declined
      add_link(10, 11, 1, network_color)  # Offer -> Accepted (network 1)
      add_link(10, 12, 1, network_color)  # Offer -> Declined (network 1)
      add_link(10, 12, 3, hiring_color)   # Offer -> Declined (hiring 3)
      
      # Sanity check
      assert len(sources) == len(targets) == len(values) == len(link_colors)
      
      # Node colors (visual guidance)
      node_colors = [
          "rgba(31,119,180,0.9)",   # Network
          "rgba(255,127,14,0.9)",   # Hiring.cafe
          "rgba(220,220,220,0.9)",  # Abandoned Lead
          "rgba(200,200,200,0.9)",  # Applied
          "rgba(220,180,180,0.9)",  # Rejected
          "rgba(200,200,220,0.9)",  # No Response
          "rgba(200,220,200,0.9)",  # Screener
          "rgba(255,200,200,0.9)",  # Rejected by Screen
          "rgba(210,210,255,0.9)",  # Full Round
          "rgba(240,200,220,0.9)",  # Rejected by Panel
          "rgba(200,255,200,0.9)",  # Offer
          "rgba(140,255,140,0.9)",  # Accepted
          "rgba(255,140,140,0.9)"   # Declined
      ]
      
      fig = go.Figure(data=[go.Sankey(
          node=dict(
              pad=18,
              thickness=18,
              line=dict(color="black", width=0.5),
              label=labels,
              color=node_colors
          ),
          link=dict(
              source=sources,
              target=targets,
              value=values,
              color=link_colors,
              hovertemplate='%{source.label} → %{target.label}: %{value}<extra></extra>'
          )
      )])
      
      fig.update_layout(
          title_text="Hiring funnel Sankey — direct source flows (no Leads node)",
          font_size=12,
          height=700,
          margin=dict(l=20, r=20, t=60, b=20)
      )
      
      fig.show()
      
      # To save as interactive HTML:
      # fig.write_html("sankey_hiring_funnel_direct.html", include_plotlyjs='cdn')
      

      Couldn’t be bothered to write this by hand for just an online comment. There’s enough that can be improved with this, but I think it’s ok to show how it can be done quite easily.

      • deegeese@sopuli.xyzOP
        link
        fedilink
        arrow-up
        1
        ·
        5 hours ago

        Thanks for sharing that. Seems like a promising vis technique but would work better with fewer final states than I used for a regular Sankey.